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 */
28
29 #include <sys/cpuvar.h>
30 #include <sys/psm.h>
31 #include <sys/archsystm.h>
32 #include <sys/apic.h>
33 #include <sys/sunddi.h>
34 #include <sys/ddi_impldefs.h>
35 #include <sys/mach_intr.h>
36 #include <sys/sysmacros.h>
37 #include <sys/trap.h>
38 #include <sys/x86_archext.h>
39 #include <sys/privregs.h>
40 #include <sys/psm_common.h>
41
42 /* Function prototypes of local apic and X2APIC */
43 static uint64_t local_apic_read(uint32_t reg);
44 static void local_apic_write(uint32_t reg, uint64_t value);
45 static int get_local_apic_pri(void);
46 static void local_apic_write_task_reg(uint64_t value);
49 static void local_x2apic_write(uint32_t msr, uint64_t value);
50 static int get_local_x2apic_pri(void);
51 static void local_x2apic_write_task_reg(uint64_t value);
52 static void local_x2apic_write_int_cmd(uint32_t cpu_id, uint32_t cmd1);
53
54 /*
55 * According to the X2APIC specification:
56 *
57 * xAPIC global enable X2APIC enable Description
58 * (IA32_APIC_BASE[11]) (IA32_APIC_BASE[10])
59 * -----------------------------------------------------------
60 * 0 0 APIC is disabled
61 * 0 1 Invalid
62 * 1 0 APIC is enabled in xAPIC mode
63 * 1 1 APIC is enabled in X2APIC mode
64 * -----------------------------------------------------------
65 */
66 int x2apic_enable = 1;
67 apic_mode_t apic_mode = LOCAL_APIC; /* Default mode is Local APIC */
68
69 /* Uses MMIO (Memory Mapped IO) */
70 static apic_reg_ops_t local_apic_regs_ops = {
71 local_apic_read,
72 local_apic_write,
73 get_local_apic_pri,
74 local_apic_write_task_reg,
75 local_apic_write_int_cmd,
76 apic_send_EOI,
77 };
78
79 /* X2APIC : Uses RDMSR/WRMSR instructions to access APIC registers */
80 static apic_reg_ops_t x2apic_regs_ops = {
81 local_x2apic_read,
82 local_x2apic_write,
83 get_local_x2apic_pri,
84 local_x2apic_write_task_reg,
85 local_x2apic_write_int_cmd,
86 apic_send_EOI,
87 };
88
277
278 apic_base_msr = rdmsr(REG_APIC_BASE_MSR);
279
280 if ((apic_base_msr & bit) == bit)
281 return (LOCAL_X2APIC);
282 else
283 return (LOCAL_APIC);
284 }
285
286 void
287 apic_set_directed_EOI_handler()
288 {
289 apic_reg_ops->apic_send_eoi = apic_send_directed_EOI;
290 }
291
292 int
293 apic_directed_EOI_supported()
294 {
295 uint32_t ver;
296
297 ver = apic_reg_ops->apic_read(APIC_VERS_REG);
298 if (ver & APIC_DIRECTED_EOI_BIT)
299 return (1);
300
301 return (0);
302 }
303
304 /*
305 * Change apic_reg_ops depending upon the apic_mode.
306 */
307 void
308 apic_change_ops()
309 {
310 if (apic_mode == LOCAL_APIC)
311 apic_reg_ops = &local_apic_regs_ops;
312 else if (apic_mode == LOCAL_X2APIC)
313 apic_reg_ops = &x2apic_regs_ops;
314 }
315
316 /*
|
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 */
29
30 #include <sys/cpuvar.h>
31 #include <sys/psm.h>
32 #include <sys/archsystm.h>
33 #include <sys/apic.h>
34 #include <sys/sunddi.h>
35 #include <sys/ddi_impldefs.h>
36 #include <sys/mach_intr.h>
37 #include <sys/sysmacros.h>
38 #include <sys/trap.h>
39 #include <sys/x86_archext.h>
40 #include <sys/privregs.h>
41 #include <sys/psm_common.h>
42
43 /* Function prototypes of local apic and X2APIC */
44 static uint64_t local_apic_read(uint32_t reg);
45 static void local_apic_write(uint32_t reg, uint64_t value);
46 static int get_local_apic_pri(void);
47 static void local_apic_write_task_reg(uint64_t value);
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
55 /*
56 * According to the X2APIC specification:
57 *
58 * xAPIC global enable X2APIC enable Description
59 * (IA32_APIC_BASE[11]) (IA32_APIC_BASE[10])
60 * -----------------------------------------------------------
61 * 0 0 APIC is disabled
62 * 0 1 Invalid
63 * 1 0 APIC is enabled in xAPIC mode
64 * 1 1 APIC is enabled in X2APIC mode
65 * -----------------------------------------------------------
66 */
67 int x2apic_enable = 1;
68 apic_mode_t apic_mode = LOCAL_APIC; /* Default mode is Local APIC */
69
70 /* See apic_directed_EOI_supported(). Currently 3-state variable. */
71 volatile int apic_directed_eoi_state = 2;
72
73 /* Uses MMIO (Memory Mapped IO) */
74 static apic_reg_ops_t local_apic_regs_ops = {
75 local_apic_read,
76 local_apic_write,
77 get_local_apic_pri,
78 local_apic_write_task_reg,
79 local_apic_write_int_cmd,
80 apic_send_EOI,
81 };
82
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
281
282 apic_base_msr = rdmsr(REG_APIC_BASE_MSR);
283
284 if ((apic_base_msr & bit) == bit)
285 return (LOCAL_X2APIC);
286 else
287 return (LOCAL_APIC);
288 }
289
290 void
291 apic_set_directed_EOI_handler()
292 {
293 apic_reg_ops->apic_send_eoi = apic_send_directed_EOI;
294 }
295
296 int
297 apic_directed_EOI_supported()
298 {
299 uint32_t ver;
300
301 /*
302 * There are some known issues with some versions of Linux KVM and QEMU
303 * where by directed EOIs do not properly function and instead get
304 * coalesced at the hypervisor, causing the host not to see interrupts.
305 * Thus, when the platform is KVM, we would like to disable it by
306 * default, but keep it available otherwise.
307 *
308 * We use a three-state variable (apic_directed_eoi_state) to determine
309 * how we handle directed EOI.
310 *
311 * 0 --> Don't do directed EOI at all.
312 * 1 --> Do directed EOI if available, no matter the HW environment.
313 * 2 --> Don't do directed EOI on KVM, but do it otherwise if available.
314 *
315 * If some grinning weirdo put something else in there, treat it as '2'
316 * (i.e. the current default).
317 *
318 * Note, at this time illumos KVM does not identify as KVM. If it does,
319 * we'll need to do some work to determine if it should be caught by
320 * this or if it should show up as its own value of platform_type.
321 */
322 switch (apic_directed_eoi_state) {
323 case 0:
324 /* Don't do it at all. */
325 return (0);
326 case 1:
327 break;
328 case 2:
329 default:
330 /* Only do it if we aren't on KVM. */
331 if (get_hwenv() == HW_KVM)
332 return (0);
333 /* FALLTHRU */
334 }
335
336 ver = apic_reg_ops->apic_read(APIC_VERS_REG);
337 if (ver & APIC_DIRECTED_EOI_BIT)
338 return (1);
339
340 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 /*
|