Print this page
8620 pcplusmp shouldn't support x2APIC mode
Reviewed by: Robert Mustacchi <rm@joyent.com>
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/i86pc/io/pcplusmp/apic_regops.c
+++ new/usr/src/uts/i86pc/io/pcplusmp/apic_regops.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
↓ open down ↓ |
17 lines elided |
↑ open up ↑ |
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 23 * Use is subject to license terms.
24 24 */
25 25 /*
26 26 * Copyright 2014 Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
27 27 * Copyright (c) 2014 by Delphix. All rights reserved.
28 + * Copyright 2017 Joyent, Inc.
28 29 */
29 30
30 31 #include <sys/cpuvar.h>
31 32 #include <sys/psm.h>
32 33 #include <sys/archsystm.h>
33 34 #include <sys/apic.h>
34 35 #include <sys/sunddi.h>
35 36 #include <sys/ddi_impldefs.h>
36 37 #include <sys/mach_intr.h>
37 38 #include <sys/sysmacros.h>
38 39 #include <sys/trap.h>
39 40 #include <sys/x86_archext.h>
40 41 #include <sys/privregs.h>
41 42 #include <sys/psm_common.h>
42 43
43 -/* Function prototypes of local apic and X2APIC */
44 +/* Function prototypes of local apic */
44 45 static uint64_t local_apic_read(uint32_t reg);
45 46 static void local_apic_write(uint32_t reg, uint64_t value);
46 47 static int get_local_apic_pri(void);
47 48 static void local_apic_write_task_reg(uint64_t value);
48 49 static void local_apic_write_int_cmd(uint32_t cpu_id, uint32_t cmd1);
49 -static uint64_t local_x2apic_read(uint32_t msr);
50 -static void local_x2apic_write(uint32_t msr, uint64_t value);
51 -static int get_local_x2apic_pri(void);
52 -static void local_x2apic_write_task_reg(uint64_t value);
53 -static void local_x2apic_write_int_cmd(uint32_t cpu_id, uint32_t cmd1);
54 50
55 51 /*
56 52 * According to the X2APIC specification:
57 53 *
58 54 * xAPIC global enable X2APIC enable Description
59 55 * (IA32_APIC_BASE[11]) (IA32_APIC_BASE[10])
60 56 * -----------------------------------------------------------
61 57 * 0 0 APIC is disabled
62 58 * 0 1 Invalid
63 59 * 1 0 APIC is enabled in xAPIC mode
64 60 * 1 1 APIC is enabled in X2APIC mode
65 61 * -----------------------------------------------------------
66 62 */
67 -int x2apic_enable = 1;
68 63 apic_mode_t apic_mode = LOCAL_APIC; /* Default mode is Local APIC */
69 64
70 65 /* See apic_directed_EOI_supported(). Currently 3-state variable. */
71 66 volatile int apic_directed_eoi_state = 2;
72 67
73 68 /* Uses MMIO (Memory Mapped IO) */
74 -static apic_reg_ops_t local_apic_regs_ops = {
69 +apic_reg_ops_t local_apic_regs_ops = {
75 70 local_apic_read,
76 71 local_apic_write,
77 72 get_local_apic_pri,
78 73 local_apic_write_task_reg,
79 74 local_apic_write_int_cmd,
80 75 apic_send_EOI,
81 76 };
82 77
83 -/* X2APIC : Uses RDMSR/WRMSR instructions to access APIC registers */
84 -static apic_reg_ops_t x2apic_regs_ops = {
85 - local_x2apic_read,
86 - local_x2apic_write,
87 - get_local_x2apic_pri,
88 - local_x2apic_write_task_reg,
89 - local_x2apic_write_int_cmd,
90 - apic_send_EOI,
91 -};
92 -
93 78 int apic_have_32bit_cr8 = 0;
94 79
95 80 /* The default ops is local APIC (Memory Mapped IO) */
96 81 apic_reg_ops_t *apic_reg_ops = &local_apic_regs_ops;
97 82
98 83 /*
99 84 * APIC register ops related data sturctures and functions.
100 85 */
101 86 void apic_send_EOI();
102 87 void apic_send_directed_EOI(uint32_t irq);
103 88
104 -#define X2APIC_ENABLE_BIT 10
105 -
106 89 /*
107 90 * Local APIC Implementation
108 91 */
109 92 static uint64_t
110 93 local_apic_read(uint32_t reg)
111 94 {
112 95 return ((uint32_t)apicadr[reg]);
113 96 }
114 97
115 98 static void
116 99 local_apic_write(uint32_t reg, uint64_t value)
117 100 {
118 101 apicadr[reg] = (uint32_t)value;
119 102 }
120 103
121 104 static int
122 105 get_local_apic_pri(void)
123 106 {
124 107 #if defined(__amd64)
125 108 return ((int)getcr8());
126 109 #else
127 110 if (apic_have_32bit_cr8)
128 111 return ((int)getcr8());
129 112 return (apicadr[APIC_TASK_REG]);
130 113 #endif
131 114 }
132 115
133 116 static void
134 117 local_apic_write_task_reg(uint64_t value)
135 118 {
136 119 #if defined(__amd64)
137 120 setcr8((ulong_t)(value >> APIC_IPL_SHIFT));
138 121 #else
139 122 if (apic_have_32bit_cr8)
140 123 setcr8((ulong_t)(value >> APIC_IPL_SHIFT));
141 124 else
142 125 apicadr[APIC_TASK_REG] = (uint32_t)value;
↓ open down ↓ |
27 lines elided |
↑ open up ↑ |
143 126 #endif
144 127 }
145 128
146 129 static void
147 130 local_apic_write_int_cmd(uint32_t cpu_id, uint32_t cmd1)
148 131 {
149 132 apicadr[APIC_INT_CMD2] = cpu_id << APIC_ICR_ID_BIT_OFFSET;
150 133 apicadr[APIC_INT_CMD1] = cmd1;
151 134 }
152 135
153 -/*
154 - * X2APIC Implementation.
155 - */
156 -static uint64_t
157 -local_x2apic_read(uint32_t msr)
158 -{
159 - uint64_t i;
160 136
161 - i = (uint64_t)(rdmsr(REG_X2APIC_BASE_MSR + (msr >> 2)) & 0xffffffff);
162 - return (i);
163 -}
164 -
165 -static void
166 -local_x2apic_write(uint32_t msr, uint64_t value)
167 -{
168 - uint64_t tmp;
169 -
170 - if (msr != APIC_EOI_REG) {
171 - tmp = rdmsr(REG_X2APIC_BASE_MSR + (msr >> 2));
172 - tmp = (tmp & 0xffffffff00000000) | value;
173 - } else {
174 - tmp = 0;
175 - }
176 -
177 - wrmsr((REG_X2APIC_BASE_MSR + (msr >> 2)), tmp);
178 -}
179 -
180 -static int
181 -get_local_x2apic_pri(void)
182 -{
183 - return (rdmsr(REG_X2APIC_BASE_MSR + (APIC_TASK_REG >> 2)));
184 -}
185 -
186 -static void
187 -local_x2apic_write_task_reg(uint64_t value)
188 -{
189 - X2APIC_WRITE(APIC_TASK_REG, value);
190 -}
191 -
192 -static void
193 -local_x2apic_write_int_cmd(uint32_t cpu_id, uint32_t cmd1)
194 -{
195 - wrmsr((REG_X2APIC_BASE_MSR + (APIC_INT_CMD1 >> 2)),
196 - (((uint64_t)cpu_id << 32) | cmd1));
197 -}
198 -
199 137 /*ARGSUSED*/
200 138 void
201 139 apic_send_EOI(uint32_t irq)
202 140 {
203 141 apic_reg_ops->apic_write(APIC_EOI_REG, 0);
204 142 }
205 143
206 144 /*
207 145 * Support for Directed EOI capability is available in both the xAPIC
208 146 * and x2APIC mode.
209 147 */
210 148 void
211 149 apic_send_directed_EOI(uint32_t irq)
212 150 {
213 151 uchar_t ioapicindex;
214 152 uchar_t vector;
215 153 apic_irq_t *apic_irq;
216 154 short intr_index;
217 155
218 156 /*
219 157 * Following the EOI to the local APIC unit, perform a directed
220 158 * EOI to the IOxAPIC generating the interrupt by writing to its
221 159 * EOI register.
222 160 *
223 161 * A broadcast EOI is not generated.
224 162 */
225 163 apic_reg_ops->apic_write(APIC_EOI_REG, 0);
226 164
227 165 apic_irq = apic_irq_table[irq];
228 166 while (apic_irq) {
↓ open down ↓ |
20 lines elided |
↑ open up ↑ |
229 167 intr_index = apic_irq->airq_mps_intr_index;
230 168 if (intr_index == ACPI_INDEX || intr_index >= 0) {
231 169 ioapicindex = apic_irq->airq_ioapicindex;
232 170 vector = apic_irq->airq_vector;
233 171 ioapic_write_eoi(ioapicindex, vector);
234 172 }
235 173 apic_irq = apic_irq->airq_next;
236 174 }
237 175 }
238 176
239 -int
240 -apic_detect_x2apic(void)
241 -{
242 - if (x2apic_enable == 0)
243 - return (0);
244 -
245 - return (is_x86_feature(x86_featureset, X86FSET_X2APIC));
246 -}
247 -
248 -void
249 -apic_enable_x2apic(void)
250 -{
251 - uint64_t apic_base_msr;
252 -
253 - if (apic_local_mode() == LOCAL_X2APIC) {
254 - /* BIOS apparently has enabled X2APIC */
255 - if (apic_mode != LOCAL_X2APIC)
256 - x2apic_update_psm();
257 - return;
258 - }
259 -
260 - /*
261 - * This is the first time we are enabling X2APIC on this CPU
262 - */
263 - apic_base_msr = rdmsr(REG_APIC_BASE_MSR);
264 - apic_base_msr = apic_base_msr | (0x1 << X2APIC_ENABLE_BIT);
265 - wrmsr(REG_APIC_BASE_MSR, apic_base_msr);
266 -
267 - if (apic_mode != LOCAL_X2APIC)
268 - x2apic_update_psm();
269 -}
270 -
271 177 /*
272 178 * Determine which mode the current CPU is in. See the table above.
273 179 * (IA32_APIC_BASE[11]) (IA32_APIC_BASE[10])
274 180 */
275 181 int
276 182 apic_local_mode(void)
277 183 {
278 184 uint64_t apic_base_msr;
279 185 int bit = ((0x1 << (X2APIC_ENABLE_BIT + 1)) |
280 186 (0x1 << X2APIC_ENABLE_BIT));
281 187
282 188 apic_base_msr = rdmsr(REG_APIC_BASE_MSR);
283 189
284 190 if ((apic_base_msr & bit) == bit)
285 191 return (LOCAL_X2APIC);
286 192 else
287 193 return (LOCAL_APIC);
288 194 }
289 195
290 196 void
291 197 apic_set_directed_EOI_handler()
292 198 {
293 199 apic_reg_ops->apic_send_eoi = apic_send_directed_EOI;
294 200 }
295 201
296 202 int
297 203 apic_directed_EOI_supported()
298 204 {
299 205 uint32_t ver;
300 206
301 207 /*
302 208 * There are some known issues with some versions of Linux KVM and QEMU
303 209 * where by directed EOIs do not properly function and instead get
304 210 * coalesced at the hypervisor, causing the host not to see interrupts.
305 211 * Thus, when the platform is KVM, we would like to disable it by
306 212 * default, but keep it available otherwise.
307 213 *
308 214 * We use a three-state variable (apic_directed_eoi_state) to determine
309 215 * how we handle directed EOI.
310 216 *
311 217 * 0 --> Don't do directed EOI at all.
312 218 * 1 --> Do directed EOI if available, no matter the HW environment.
313 219 * 2 --> Don't do directed EOI on KVM, but do it otherwise if available.
314 220 *
315 221 * If some grinning weirdo put something else in there, treat it as '2'
316 222 * (i.e. the current default).
317 223 *
318 224 * Note, at this time illumos KVM does not identify as KVM. If it does,
319 225 * we'll need to do some work to determine if it should be caught by
320 226 * this or if it should show up as its own value of platform_type.
321 227 */
322 228 switch (apic_directed_eoi_state) {
323 229 case 0:
324 230 /* Don't do it at all. */
325 231 return (0);
326 232 case 1:
327 233 break;
328 234 case 2:
329 235 default:
330 236 /* Only do it if we aren't on KVM. */
↓ open down ↓ |
50 lines elided |
↑ open up ↑ |
331 237 if (get_hwenv() == HW_KVM)
332 238 return (0);
333 239 /* FALLTHRU */
334 240 }
335 241
336 242 ver = apic_reg_ops->apic_read(APIC_VERS_REG);
337 243 if (ver & APIC_DIRECTED_EOI_BIT)
338 244 return (1);
339 245
340 246 return (0);
341 -}
342 -
343 -/*
344 - * Change apic_reg_ops depending upon the apic_mode.
345 - */
346 -void
347 -apic_change_ops()
348 -{
349 - if (apic_mode == LOCAL_APIC)
350 - apic_reg_ops = &local_apic_regs_ops;
351 - else if (apic_mode == LOCAL_X2APIC)
352 - apic_reg_ops = &x2apic_regs_ops;
353 -}
354 -
355 -/*
356 - * Generates an interprocessor interrupt to another CPU when X2APIC mode is
357 - * enabled.
358 - */
359 -void
360 -x2apic_send_ipi(int cpun, int ipl)
361 -{
362 - int vector;
363 - ulong_t flag;
364 -
365 - ASSERT(apic_mode == LOCAL_X2APIC);
366 -
367 - /*
368 - * With X2APIC, Intel relaxed the semantics of the
369 - * WRMSR instruction such that references to the X2APIC
370 - * MSR registers are no longer serializing instructions.
371 - * The code that initiates IPIs assumes that some sort
372 - * of memory serialization occurs. The old APIC code
373 - * did a write to uncachable memory mapped registers.
374 - * Any reference to uncached memory is a serializing
375 - * operation. To mimic those semantics here, we do an
376 - * atomic operation, which translates to a LOCK OR instruction,
377 - * which is serializing.
378 - */
379 - atomic_or_ulong(&flag, 1);
380 -
381 - vector = apic_resv_vector[ipl];
382 -
383 - flag = intr_clear();
384 -
385 - /*
386 - * According to X2APIC specification in section '2.3.5.1' of
387 - * Interrupt Command Register Semantics, the semantics of
388 - * programming Interrupt Command Register to dispatch an interrupt
389 - * is simplified. A single MSR write to the 64-bit ICR is required
390 - * for dispatching an interrupt. Specifically with the 64-bit MSR
391 - * interface to ICR, system software is not required to check the
392 - * status of the delivery status bit prior to writing to the ICR
393 - * to send an IPI. With the removal of the Delivery Status bit,
394 - * system software no longer has a reason to read the ICR. It remains
395 - * readable only to aid in debugging.
396 - */
397 -#ifdef DEBUG
398 - APIC_AV_PENDING_SET();
399 -#endif /* DEBUG */
400 -
401 - if ((cpun == psm_get_cpu_id())) {
402 - X2APIC_WRITE(X2APIC_SELF_IPI, vector);
403 - } else {
404 - apic_reg_ops->apic_write_int_cmd(
405 - apic_cpus[cpun].aci_local_id, vector);
406 - }
407 -
408 - intr_restore(flag);
409 -}
410 -
411 -/*
412 - * Generates IPI to another CPU depending on the local APIC mode.
413 - * apic_send_ipi() and x2apic_send_ipi() depends on the configured
414 - * mode of the local APIC, but that may not match the actual mode
415 - * early in CPU startup.
416 - *
417 - * Any changes made to this routine must be accompanied by similar
418 - * changes to apic_send_ipi().
419 - */
420 -void
421 -apic_common_send_ipi(int cpun, int ipl)
422 -{
423 - int vector;
424 - ulong_t flag;
425 - int mode = apic_local_mode();
426 -
427 - if (mode == LOCAL_X2APIC) {
428 - x2apic_send_ipi(cpun, ipl);
429 - return;
430 - }
431 -
432 - ASSERT(mode == LOCAL_APIC);
433 -
434 - vector = apic_resv_vector[ipl];
435 - ASSERT((vector >= APIC_BASE_VECT) && (vector <= APIC_SPUR_INTR));
436 - flag = intr_clear();
437 - while (local_apic_regs_ops.apic_read(APIC_INT_CMD1) & AV_PENDING)
438 - apic_ret();
439 - local_apic_regs_ops.apic_write_int_cmd(apic_cpus[cpun].aci_local_id,
440 - vector);
441 - intr_restore(flag);
442 247 }
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX