summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHans Rosenfeld <hans.rosenfeld@joyent.com>2017-04-26 14:02:21 +0200
committerHans Rosenfeld <hans.rosenfeld@joyent.com>2017-05-08 08:54:38 +0000
commit56f03ffa93d78b09f5d08328b97ee73234660f22 (patch)
tree7ddbdf5ece5aa89d7345cce24f2401e799dad9be
parent6a968985a46f0a8d77b8c029edb43dfd4a44ae66 (diff)
downloadillumos-joyent-56f03ffa93d78b09f5d08328b97ee73234660f22.tar.gz
OS-6085 pcplusmp shouldn't support x2APIC mode
Reviewed by: Robert Mustacchi <rm@joyent.com> Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com> Approved by: Jerry Jelinek <jerry.jelinek@joyent.com>
-rw-r--r--usr/src/uts/i86pc/Makefile.files4
-rw-r--r--usr/src/uts/i86pc/apix/Makefile6
-rw-r--r--usr/src/uts/i86pc/io/apix/apix.c42
-rw-r--r--usr/src/uts/i86pc/io/apix/apix_regops.c252
-rw-r--r--usr/src/uts/i86pc/io/pcplusmp/apic.c132
-rw-r--r--usr/src/uts/i86pc/io/pcplusmp/apic_common.c43
-rw-r--r--usr/src/uts/i86pc/io/pcplusmp/apic_regops.c201
-rw-r--r--usr/src/uts/i86pc/sys/apic.h6
8 files changed, 341 insertions, 345 deletions
diff --git a/usr/src/uts/i86pc/Makefile.files b/usr/src/uts/i86pc/Makefile.files
index f3f10e1b6c..26d7f3f039 100644
--- a/usr/src/uts/i86pc/Makefile.files
+++ b/usr/src/uts/i86pc/Makefile.files
@@ -23,7 +23,7 @@
# Copyright (c) 1992, 2010, Oracle and/or its affiliates. All rights reserved.
#
# Copyright (c) 2010, Intel Corporation.
-# Copyright 2016 Joyent, Inc.
+# Copyright 2017 Joyent, Inc.
#
# This Makefile defines file modules in the directory uts/i86pc
# and its children. These are the source files which are i86pc
@@ -200,7 +200,7 @@ PCPLUSMP_OBJS += apic.o apic_regops.o psm_common.o apic_introp.o \
hpet_acpi.o apic_common.o apic_timer.o
APIX_OBJS += apix.o apic_regops.o psm_common.o apix_intr.o apix_utils.o \
apix_irm.o mp_platform_common.o hpet_acpi.o apic_common.o \
- apic_timer.o
+ apic_timer.o apix_regops.o
ACPI_DRV_OBJS += acpi_drv.o acpi_video.o
diff --git a/usr/src/uts/i86pc/apix/Makefile b/usr/src/uts/i86pc/apix/Makefile
index 18100b7ced..c562707a10 100644
--- a/usr/src/uts/i86pc/apix/Makefile
+++ b/usr/src/uts/i86pc/apix/Makefile
@@ -22,12 +22,12 @@
# uts/i86pc/apix/Makefile
#
# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
-# Copyright 2016, Joyent, Inc.
+# Copyright 2017, Joyent, Inc.
#
-# This makefile drives the production of the pcplusmp "mach"
+# This makefile drives the production of the apix "mach"
# kernel module.
#
-# pcplusmp implementation architecture dependent
+# apix implementation architecture dependent
#
#
diff --git a/usr/src/uts/i86pc/io/apix/apix.c b/usr/src/uts/i86pc/io/apix/apix.c
index 9bacbd7c5e..85890a1db6 100644
--- a/usr/src/uts/i86pc/io/apix/apix.c
+++ b/usr/src/uts/i86pc/io/apix/apix.c
@@ -221,6 +221,9 @@ int apix_nipis = 16; /* Maximum number of IPIs */
*/
int apix_cpu_nvectors = APIX_NVECTOR;
+/* number of CPUs in power-on transition state */
+static int apic_poweron_cnt = 0;
+
/* gcpu.h */
extern void apic_do_interrupt(struct regs *rp, trap_trace_rec_t *ttp);
@@ -2560,6 +2563,45 @@ apix_intx_xlate_vector(dev_info_t *dip, int inum, struct intrspec *ispec)
return (vecp);
}
+/*
+ * Switch between safe and x2APIC IPI sending method.
+ * The CPU may power on in xapic mode or x2apic mode. If the CPU needs to send
+ * an IPI to other CPUs before entering x2APIC mode, it still needs to use the
+ * xAPIC method. Before sending a StartIPI to the target CPU, psm_send_ipi will
+ * be changed to apic_common_send_ipi, which detects current local APIC mode and
+ * use the right method to send an IPI. If some CPUs fail to start up,
+ * apic_poweron_cnt won't return to zero, so apic_common_send_ipi will always be
+ * used. psm_send_ipi can't be simply changed back to x2apic_send_ipi if some
+ * CPUs failed to start up because those failed CPUs may recover itself later at
+ * unpredictable time.
+ */
+void
+apic_switch_ipi_callback(boolean_t enter)
+{
+ ulong_t iflag;
+ struct psm_ops *pops = psmops;
+
+ iflag = intr_clear();
+ lock_set(&apic_mode_switch_lock);
+ if (enter) {
+ ASSERT(apic_poweron_cnt >= 0);
+ if (apic_poweron_cnt == 0) {
+ pops->psm_send_ipi = apic_common_send_ipi;
+ send_dirintf = pops->psm_send_ipi;
+ }
+ apic_poweron_cnt++;
+ } else {
+ ASSERT(apic_poweron_cnt > 0);
+ apic_poweron_cnt--;
+ if (apic_poweron_cnt == 0) {
+ pops->psm_send_ipi = x2apic_send_ipi;
+ send_dirintf = pops->psm_send_ipi;
+ }
+ }
+ lock_clear(&apic_mode_switch_lock);
+ intr_restore(iflag);
+}
+
/* stub function */
int
apix_loaded(void)
diff --git a/usr/src/uts/i86pc/io/apix/apix_regops.c b/usr/src/uts/i86pc/io/apix/apix_regops.c
new file mode 100644
index 0000000000..1432b66a81
--- /dev/null
+++ b/usr/src/uts/i86pc/io/apix/apix_regops.c
@@ -0,0 +1,252 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+/*
+ * Copyright 2014 Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
+ * Copyright (c) 2014 by Delphix. All rights reserved.
+ * Copyright 2017 Joyent, Inc.
+ */
+
+#include <sys/cpuvar.h>
+#include <sys/psm.h>
+#include <sys/archsystm.h>
+#include <sys/apic.h>
+#include <sys/sunddi.h>
+#include <sys/ddi_impldefs.h>
+#include <sys/mach_intr.h>
+#include <sys/sysmacros.h>
+#include <sys/trap.h>
+#include <sys/x86_archext.h>
+#include <sys/privregs.h>
+#include <sys/psm_common.h>
+
+/* Function prototypes of X2APIC */
+static uint64_t local_x2apic_read(uint32_t msr);
+static void local_x2apic_write(uint32_t msr, uint64_t value);
+static int get_local_x2apic_pri(void);
+static void local_x2apic_write_task_reg(uint64_t value);
+static void local_x2apic_write_int_cmd(uint32_t cpu_id, uint32_t cmd1);
+
+/*
+ * According to the X2APIC specification:
+ *
+ * xAPIC global enable X2APIC enable Description
+ * (IA32_APIC_BASE[11]) (IA32_APIC_BASE[10])
+ * -----------------------------------------------------------
+ * 0 0 APIC is disabled
+ * 0 1 Invalid
+ * 1 0 APIC is enabled in xAPIC mode
+ * 1 1 APIC is enabled in X2APIC mode
+ * -----------------------------------------------------------
+ */
+int x2apic_enable = 1;
+
+/* X2APIC : Uses RDMSR/WRMSR instructions to access APIC registers */
+static apic_reg_ops_t x2apic_regs_ops = {
+ local_x2apic_read,
+ local_x2apic_write,
+ get_local_x2apic_pri,
+ local_x2apic_write_task_reg,
+ local_x2apic_write_int_cmd,
+ apic_send_EOI,
+};
+
+/*
+ * X2APIC Implementation.
+ */
+static uint64_t
+local_x2apic_read(uint32_t msr)
+{
+ uint64_t i;
+
+ i = (uint64_t)(rdmsr(REG_X2APIC_BASE_MSR + (msr >> 2)) & 0xffffffff);
+ return (i);
+}
+
+static void
+local_x2apic_write(uint32_t msr, uint64_t value)
+{
+ uint64_t tmp;
+
+ if (msr != APIC_EOI_REG) {
+ tmp = rdmsr(REG_X2APIC_BASE_MSR + (msr >> 2));
+ tmp = (tmp & 0xffffffff00000000) | value;
+ } else {
+ tmp = 0;
+ }
+
+ wrmsr((REG_X2APIC_BASE_MSR + (msr >> 2)), tmp);
+}
+
+static int
+get_local_x2apic_pri(void)
+{
+ return (rdmsr(REG_X2APIC_BASE_MSR + (APIC_TASK_REG >> 2)));
+}
+
+static void
+local_x2apic_write_task_reg(uint64_t value)
+{
+ X2APIC_WRITE(APIC_TASK_REG, value);
+}
+
+static void
+local_x2apic_write_int_cmd(uint32_t cpu_id, uint32_t cmd1)
+{
+ wrmsr((REG_X2APIC_BASE_MSR + (APIC_INT_CMD1 >> 2)),
+ (((uint64_t)cpu_id << 32) | cmd1));
+}
+
+int
+apic_detect_x2apic(void)
+{
+ if (x2apic_enable == 0)
+ return (0);
+
+ return (is_x86_feature(x86_featureset, X86FSET_X2APIC));
+}
+
+void
+apic_enable_x2apic(void)
+{
+ uint64_t apic_base_msr;
+
+ if (apic_local_mode() == LOCAL_X2APIC) {
+ /* BIOS apparently has enabled X2APIC */
+ if (apic_mode != LOCAL_X2APIC)
+ x2apic_update_psm();
+ return;
+ }
+
+ /*
+ * This is the first time we are enabling X2APIC on this CPU
+ */
+ apic_base_msr = rdmsr(REG_APIC_BASE_MSR);
+ apic_base_msr = apic_base_msr | (0x1 << X2APIC_ENABLE_BIT);
+ wrmsr(REG_APIC_BASE_MSR, apic_base_msr);
+
+ if (apic_mode != LOCAL_X2APIC)
+ x2apic_update_psm();
+}
+
+/*
+ * Change apic_reg_ops depending upon the apic_mode.
+ */
+void
+apic_change_ops()
+{
+ if (apic_mode == LOCAL_APIC)
+ apic_reg_ops = &local_apic_regs_ops;
+ else if (apic_mode == LOCAL_X2APIC)
+ apic_reg_ops = &x2apic_regs_ops;
+}
+
+/*
+ * Generates an interprocessor interrupt to another CPU when X2APIC mode is
+ * enabled.
+ */
+void
+x2apic_send_ipi(int cpun, int ipl)
+{
+ int vector;
+ ulong_t flag;
+
+ ASSERT(apic_mode == LOCAL_X2APIC);
+
+ /*
+ * With X2APIC, Intel relaxed the semantics of the
+ * WRMSR instruction such that references to the X2APIC
+ * MSR registers are no longer serializing instructions.
+ * The code that initiates IPIs assumes that some sort
+ * of memory serialization occurs. The old APIC code
+ * did a write to uncachable memory mapped registers.
+ * Any reference to uncached memory is a serializing
+ * operation. To mimic those semantics here, we do an
+ * atomic operation, which translates to a LOCK OR instruction,
+ * which is serializing.
+ */
+ atomic_or_ulong(&flag, 1);
+
+ vector = apic_resv_vector[ipl];
+
+ flag = intr_clear();
+
+ /*
+ * According to X2APIC specification in section '2.3.5.1' of
+ * Interrupt Command Register Semantics, the semantics of
+ * programming Interrupt Command Register to dispatch an interrupt
+ * is simplified. A single MSR write to the 64-bit ICR is required
+ * for dispatching an interrupt. Specifically with the 64-bit MSR
+ * interface to ICR, system software is not required to check the
+ * status of the delivery status bit prior to writing to the ICR
+ * to send an IPI. With the removal of the Delivery Status bit,
+ * system software no longer has a reason to read the ICR. It remains
+ * readable only to aid in debugging.
+ */
+#ifdef DEBUG
+ APIC_AV_PENDING_SET();
+#endif /* DEBUG */
+
+ if ((cpun == psm_get_cpu_id())) {
+ X2APIC_WRITE(X2APIC_SELF_IPI, vector);
+ } else {
+ apic_reg_ops->apic_write_int_cmd(
+ apic_cpus[cpun].aci_local_id, vector);
+ }
+
+ intr_restore(flag);
+}
+
+/*
+ * Generates IPI to another CPU depending on the local APIC mode.
+ * apic_send_ipi() and x2apic_send_ipi() depends on the configured
+ * mode of the local APIC, but that may not match the actual mode
+ * early in CPU startup.
+ *
+ * Any changes made to this routine must be accompanied by similar
+ * changes to apic_send_ipi().
+ */
+void
+apic_common_send_ipi(int cpun, int ipl)
+{
+ int vector;
+ ulong_t flag;
+ int mode = apic_local_mode();
+
+ if (mode == LOCAL_X2APIC) {
+ x2apic_send_ipi(cpun, ipl);
+ return;
+ }
+
+ ASSERT(mode == LOCAL_APIC);
+
+ vector = apic_resv_vector[ipl];
+ ASSERT((vector >= APIC_BASE_VECT) && (vector <= APIC_SPUR_INTR));
+ flag = intr_clear();
+ while (local_apic_regs_ops.apic_read(APIC_INT_CMD1) & AV_PENDING)
+ apic_ret();
+ local_apic_regs_ops.apic_write_int_cmd(apic_cpus[cpun].aci_local_id,
+ vector);
+ intr_restore(flag);
+}
diff --git a/usr/src/uts/i86pc/io/pcplusmp/apic.c b/usr/src/uts/i86pc/io/pcplusmp/apic.c
index cd06f76967..8523112173 100644
--- a/usr/src/uts/i86pc/io/pcplusmp/apic.c
+++ b/usr/src/uts/i86pc/io/pcplusmp/apic.c
@@ -100,7 +100,6 @@ static void apic_picinit(void);
static int apic_post_cpu_start(void);
static int apic_intr_enter(int ipl, int *vect);
static void apic_setspl(int ipl);
-static void x2apic_setspl(int ipl);
static int apic_addspl(int ipl, int vector, int min_ipl, int max_ipl);
static int apic_delspl(int ipl, int vector, int min_ipl, int max_ipl);
static int apic_disable_intr(processorid_t cpun);
@@ -312,22 +311,19 @@ apic_init_intr(void)
apic_reg_ops->apic_write_task_reg(APIC_MASK_ALL);
- if (apic_mode == LOCAL_APIC) {
- /*
- * We are running APIC in MMIO mode.
- */
- if (apic_flat_model) {
- apic_reg_ops->apic_write(APIC_FORMAT_REG,
- APIC_FLAT_MODEL);
- } else {
- apic_reg_ops->apic_write(APIC_FORMAT_REG,
- APIC_CLUSTER_MODEL);
- }
+ ASSERT(apic_mode == LOCAL_APIC);
- apic_reg_ops->apic_write(APIC_DEST_REG,
- AV_HIGH_ORDER >> cpun);
+ /*
+ * We are running APIC in MMIO mode.
+ */
+ if (apic_flat_model) {
+ apic_reg_ops->apic_write(APIC_FORMAT_REG, APIC_FLAT_MODEL);
+ } else {
+ apic_reg_ops->apic_write(APIC_FORMAT_REG, APIC_CLUSTER_MODEL);
}
+ apic_reg_ops->apic_write(APIC_DEST_REG, AV_HIGH_ORDER >> cpun);
+
if (apic_directed_EOI_supported()) {
/*
* Setting the 12th bit in the Spurious Interrupt Vector
@@ -633,24 +629,6 @@ apic_intr_enter(int ipl, int *vectorp)
return (nipl);
}
-/*
- * This macro is a common code used by MMIO local apic and X2APIC
- * local apic.
- */
-#define APIC_INTR_EXIT() \
-{ \
- cpu_infop = &apic_cpus[psm_get_cpu_id()]; \
- if (apic_level_intr[irq]) \
- apic_reg_ops->apic_send_eoi(irq); \
- cpu_infop->aci_curipl = (uchar_t)prev_ipl; \
- /* ISR above current pri could not be in progress */ \
- cpu_infop->aci_ISR_in_progress &= (2 << prev_ipl) - 1; \
-}
-
-/*
- * Any changes made to this function must also change X2APIC
- * version of intr_exit.
- */
void
apic_intr_exit(int prev_ipl, int irq)
{
@@ -658,35 +636,22 @@ apic_intr_exit(int prev_ipl, int irq)
apic_reg_ops->apic_write_task_reg(apic_ipltopri[prev_ipl]);
- APIC_INTR_EXIT();
-}
-
-/*
- * Same as apic_intr_exit() except it uses MSR rather than MMIO
- * to access local apic registers.
- */
-void
-x2apic_intr_exit(int prev_ipl, int irq)
-{
- apic_cpus_info_t *cpu_infop;
-
- X2APIC_WRITE(APIC_TASK_REG, apic_ipltopri[prev_ipl]);
- APIC_INTR_EXIT();
+ cpu_infop = &apic_cpus[psm_get_cpu_id()];
+ if (apic_level_intr[irq])
+ apic_reg_ops->apic_send_eoi(irq);
+ cpu_infop->aci_curipl = (uchar_t)prev_ipl;
+ /* ISR above current pri could not be in progress */
+ cpu_infop->aci_ISR_in_progress &= (2 << prev_ipl) - 1;
}
intr_exit_fn_t
psm_intr_exit_fn(void)
{
- if (apic_mode == LOCAL_X2APIC)
- return (x2apic_intr_exit);
-
return (apic_intr_exit);
}
/*
* Mask all interrupts below or equal to the given IPL.
- * Any changes made to this function must also change X2APIC
- * version of setspl.
*/
static void
apic_setspl(int ipl)
@@ -704,19 +669,6 @@ apic_setspl(int ipl)
(void) apic_reg_ops->apic_get_pri();
}
-/*
- * X2APIC version of setspl.
- * Mask all interrupts below or equal to the given IPL
- */
-static void
-x2apic_setspl(int ipl)
-{
- X2APIC_WRITE(APIC_TASK_REG, apic_ipltopri[ipl]);
-
- /* interrupts at ipl above this cannot be in progress */
- apic_cpus[psm_get_cpu_id()].aci_ISR_in_progress &= (2 << ipl) - 1;
-}
-
/*ARGSUSED*/
static int
apic_addspl(int irqno, int ipl, int min_ipl, int max_ipl)
@@ -739,26 +691,6 @@ apic_post_cpu_start(void)
/* We know this CPU + BSP started successfully. */
cpus_started++;
- /*
- * On BSP we would have enabled X2APIC, if supported by processor,
- * in acpi_probe(), but on AP we do it here.
- *
- * We enable X2APIC mode only if BSP is running in X2APIC & the
- * local APIC mode of the current CPU is MMIO (xAPIC).
- */
- if (apic_mode == LOCAL_X2APIC && apic_detect_x2apic() &&
- apic_local_mode() == LOCAL_APIC) {
- apic_enable_x2apic();
- }
-
- /*
- * Switch back to x2apic IPI sending method for performance when target
- * CPU has entered x2apic mode.
- */
- if (apic_mode == LOCAL_X2APIC) {
- apic_switch_ipi_callback(B_FALSE);
- }
-
splx(ipltospl(LOCK_LEVEL));
apic_init_intr();
@@ -768,12 +700,7 @@ apic_post_cpu_start(void)
*/
setcr0(getcr0() & ~(CR0_CD | CR0_NW));
-#ifdef DEBUG
APIC_AV_PENDING_SET();
-#else
- if (apic_mode == LOCAL_APIC)
- APIC_AV_PENDING_SET();
-#endif /* DEBUG */
/*
* We may be booting, or resuming from suspend; aci_status will
@@ -1330,18 +1257,25 @@ apic_get_apic_type(void)
}
void
-x2apic_update_psm(void)
+apic_switch_ipi_callback(boolean_t enter)
{
- struct psm_ops *pops = &apic_ops;
-
- ASSERT(pops != NULL);
+ ASSERT(enter == B_TRUE);
+}
- pops->psm_intr_exit = x2apic_intr_exit;
- pops->psm_setspl = x2apic_setspl;
+int
+apic_detect_x2apic(void)
+{
+ return (0);
+}
- pops->psm_send_ipi = x2apic_send_ipi;
- send_dirintf = pops->psm_send_ipi;
+void
+apic_enable_x2apic(void)
+{
+ cmn_err(CE_PANIC, "apic_enable_x2apic() called in pcplusmp");
+}
- apic_mode = LOCAL_X2APIC;
- apic_change_ops();
+void
+x2apic_update_psm(void)
+{
+ cmn_err(CE_PANIC, "x2apic_update_psm() called in pcplusmp");
}
diff --git a/usr/src/uts/i86pc/io/pcplusmp/apic_common.c b/usr/src/uts/i86pc/io/pcplusmp/apic_common.c
index 649e5ce950..7498150d49 100644
--- a/usr/src/uts/i86pc/io/pcplusmp/apic_common.c
+++ b/usr/src/uts/i86pc/io/pcplusmp/apic_common.c
@@ -23,7 +23,7 @@
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
*/
/*
- * Copyright (c) 2013, Joyent, Inc. All rights reserved.
+ * Copyright (c) 2017, Joyent, Inc. All rights reserved.
* Copyright (c) 2016 by Delphix. All rights reserved.
*/
@@ -128,8 +128,6 @@ extern void cmi_cmci_trap(void);
kmutex_t cmci_cpu_setup_lock; /* protects cmci_cpu_setup_registered */
int cmci_cpu_setup_registered;
-/* number of CPUs in power-on transition state */
-static int apic_poweron_cnt = 0;
lock_t apic_mode_switch_lock;
/*
@@ -1456,45 +1454,6 @@ apic_find_cpu(int flag)
return (acid);
}
-/*
- * Switch between safe and x2APIC IPI sending method.
- * CPU may power on in xapic mode or x2apic mode. If CPU needs to send IPI to
- * other CPUs before entering x2APIC mode, it still needs to xAPIC method.
- * Before sending StartIPI to target CPU, psm_send_ipi will be changed to
- * apic_common_send_ipi, which detects current local APIC mode and use right
- * method to send IPI. If some CPUs fail to start up, apic_poweron_cnt
- * won't return to zero, so apic_common_send_ipi will always be used.
- * psm_send_ipi can't be simply changed back to x2apic_send_ipi if some CPUs
- * failed to start up because those failed CPUs may recover itself later at
- * unpredictable time.
- */
-void
-apic_switch_ipi_callback(boolean_t enter)
-{
- ulong_t iflag;
- struct psm_ops *pops = psmops;
-
- iflag = intr_clear();
- lock_set(&apic_mode_switch_lock);
- if (enter) {
- ASSERT(apic_poweron_cnt >= 0);
- if (apic_poweron_cnt == 0) {
- pops->psm_send_ipi = apic_common_send_ipi;
- send_dirintf = pops->psm_send_ipi;
- }
- apic_poweron_cnt++;
- } else {
- ASSERT(apic_poweron_cnt > 0);
- apic_poweron_cnt--;
- if (apic_poweron_cnt == 0) {
- pops->psm_send_ipi = x2apic_send_ipi;
- send_dirintf = pops->psm_send_ipi;
- }
- }
- lock_clear(&apic_mode_switch_lock);
- intr_restore(iflag);
-}
-
void
apic_intrmap_init(int apic_mode)
{
diff --git a/usr/src/uts/i86pc/io/pcplusmp/apic_regops.c b/usr/src/uts/i86pc/io/pcplusmp/apic_regops.c
index 60ce7a3771..e0b647975d 100644
--- a/usr/src/uts/i86pc/io/pcplusmp/apic_regops.c
+++ b/usr/src/uts/i86pc/io/pcplusmp/apic_regops.c
@@ -25,6 +25,7 @@
/*
* Copyright 2014 Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
* Copyright (c) 2014 by Delphix. All rights reserved.
+ * Copyright 2017 Joyent, Inc.
*/
#include <sys/cpuvar.h>
@@ -40,17 +41,12 @@
#include <sys/privregs.h>
#include <sys/psm_common.h>
-/* Function prototypes of local apic and X2APIC */
+/* Function prototypes of local apic */
static uint64_t local_apic_read(uint32_t reg);
static void local_apic_write(uint32_t reg, uint64_t value);
static int get_local_apic_pri(void);
static void local_apic_write_task_reg(uint64_t value);
static void local_apic_write_int_cmd(uint32_t cpu_id, uint32_t cmd1);
-static uint64_t local_x2apic_read(uint32_t msr);
-static void local_x2apic_write(uint32_t msr, uint64_t value);
-static int get_local_x2apic_pri(void);
-static void local_x2apic_write_task_reg(uint64_t value);
-static void local_x2apic_write_int_cmd(uint32_t cpu_id, uint32_t cmd1);
/*
* According to the X2APIC specification:
@@ -64,14 +60,13 @@ static void local_x2apic_write_int_cmd(uint32_t cpu_id, uint32_t cmd1);
* 1 1 APIC is enabled in X2APIC mode
* -----------------------------------------------------------
*/
-int x2apic_enable = 1;
apic_mode_t apic_mode = LOCAL_APIC; /* Default mode is Local APIC */
/* See apic_directed_EOI_supported(). Currently 3-state variable. */
volatile int apic_directed_eoi_state = 2;
/* Uses MMIO (Memory Mapped IO) */
-static apic_reg_ops_t local_apic_regs_ops = {
+apic_reg_ops_t local_apic_regs_ops = {
local_apic_read,
local_apic_write,
get_local_apic_pri,
@@ -80,16 +75,6 @@ static apic_reg_ops_t local_apic_regs_ops = {
apic_send_EOI,
};
-/* X2APIC : Uses RDMSR/WRMSR instructions to access APIC registers */
-static apic_reg_ops_t x2apic_regs_ops = {
- local_x2apic_read,
- local_x2apic_write,
- get_local_x2apic_pri,
- local_x2apic_write_task_reg,
- local_x2apic_write_int_cmd,
- apic_send_EOI,
-};
-
int apic_have_32bit_cr8 = 0;
/* The default ops is local APIC (Memory Mapped IO) */
@@ -101,8 +86,6 @@ apic_reg_ops_t *apic_reg_ops = &local_apic_regs_ops;
void apic_send_EOI();
void apic_send_directed_EOI(uint32_t irq);
-#define X2APIC_ENABLE_BIT 10
-
/*
* Local APIC Implementation
*/
@@ -150,51 +133,6 @@ local_apic_write_int_cmd(uint32_t cpu_id, uint32_t cmd1)
apicadr[APIC_INT_CMD1] = cmd1;
}
-/*
- * X2APIC Implementation.
- */
-static uint64_t
-local_x2apic_read(uint32_t msr)
-{
- uint64_t i;
-
- i = (uint64_t)(rdmsr(REG_X2APIC_BASE_MSR + (msr >> 2)) & 0xffffffff);
- return (i);
-}
-
-static void
-local_x2apic_write(uint32_t msr, uint64_t value)
-{
- uint64_t tmp;
-
- if (msr != APIC_EOI_REG) {
- tmp = rdmsr(REG_X2APIC_BASE_MSR + (msr >> 2));
- tmp = (tmp & 0xffffffff00000000) | value;
- } else {
- tmp = 0;
- }
-
- wrmsr((REG_X2APIC_BASE_MSR + (msr >> 2)), tmp);
-}
-
-static int
-get_local_x2apic_pri(void)
-{
- return (rdmsr(REG_X2APIC_BASE_MSR + (APIC_TASK_REG >> 2)));
-}
-
-static void
-local_x2apic_write_task_reg(uint64_t value)
-{
- X2APIC_WRITE(APIC_TASK_REG, value);
-}
-
-static void
-local_x2apic_write_int_cmd(uint32_t cpu_id, uint32_t cmd1)
-{
- wrmsr((REG_X2APIC_BASE_MSR + (APIC_INT_CMD1 >> 2)),
- (((uint64_t)cpu_id << 32) | cmd1));
-}
/*ARGSUSED*/
void
@@ -236,38 +174,6 @@ apic_send_directed_EOI(uint32_t irq)
}
}
-int
-apic_detect_x2apic(void)
-{
- if (x2apic_enable == 0)
- return (0);
-
- return (is_x86_feature(x86_featureset, X86FSET_X2APIC));
-}
-
-void
-apic_enable_x2apic(void)
-{
- uint64_t apic_base_msr;
-
- if (apic_local_mode() == LOCAL_X2APIC) {
- /* BIOS apparently has enabled X2APIC */
- if (apic_mode != LOCAL_X2APIC)
- x2apic_update_psm();
- return;
- }
-
- /*
- * This is the first time we are enabling X2APIC on this CPU
- */
- apic_base_msr = rdmsr(REG_APIC_BASE_MSR);
- apic_base_msr = apic_base_msr | (0x1 << X2APIC_ENABLE_BIT);
- wrmsr(REG_APIC_BASE_MSR, apic_base_msr);
-
- if (apic_mode != LOCAL_X2APIC)
- x2apic_update_psm();
-}
-
/*
* Determine which mode the current CPU is in. See the table above.
* (IA32_APIC_BASE[11]) (IA32_APIC_BASE[10])
@@ -339,104 +245,3 @@ apic_directed_EOI_supported()
return (0);
}
-
-/*
- * Change apic_reg_ops depending upon the apic_mode.
- */
-void
-apic_change_ops()
-{
- if (apic_mode == LOCAL_APIC)
- apic_reg_ops = &local_apic_regs_ops;
- else if (apic_mode == LOCAL_X2APIC)
- apic_reg_ops = &x2apic_regs_ops;
-}
-
-/*
- * Generates an interprocessor interrupt to another CPU when X2APIC mode is
- * enabled.
- */
-void
-x2apic_send_ipi(int cpun, int ipl)
-{
- int vector;
- ulong_t flag;
-
- ASSERT(apic_mode == LOCAL_X2APIC);
-
- /*
- * With X2APIC, Intel relaxed the semantics of the
- * WRMSR instruction such that references to the X2APIC
- * MSR registers are no longer serializing instructions.
- * The code that initiates IPIs assumes that some sort
- * of memory serialization occurs. The old APIC code
- * did a write to uncachable memory mapped registers.
- * Any reference to uncached memory is a serializing
- * operation. To mimic those semantics here, we do an
- * atomic operation, which translates to a LOCK OR instruction,
- * which is serializing.
- */
- atomic_or_ulong(&flag, 1);
-
- vector = apic_resv_vector[ipl];
-
- flag = intr_clear();
-
- /*
- * According to X2APIC specification in section '2.3.5.1' of
- * Interrupt Command Register Semantics, the semantics of
- * programming Interrupt Command Register to dispatch an interrupt
- * is simplified. A single MSR write to the 64-bit ICR is required
- * for dispatching an interrupt. Specifically with the 64-bit MSR
- * interface to ICR, system software is not required to check the
- * status of the delivery status bit prior to writing to the ICR
- * to send an IPI. With the removal of the Delivery Status bit,
- * system software no longer has a reason to read the ICR. It remains
- * readable only to aid in debugging.
- */
-#ifdef DEBUG
- APIC_AV_PENDING_SET();
-#endif /* DEBUG */
-
- if ((cpun == psm_get_cpu_id())) {
- X2APIC_WRITE(X2APIC_SELF_IPI, vector);
- } else {
- apic_reg_ops->apic_write_int_cmd(
- apic_cpus[cpun].aci_local_id, vector);
- }
-
- intr_restore(flag);
-}
-
-/*
- * Generates IPI to another CPU depending on the local APIC mode.
- * apic_send_ipi() and x2apic_send_ipi() depends on the configured
- * mode of the local APIC, but that may not match the actual mode
- * early in CPU startup.
- *
- * Any changes made to this routine must be accompanied by similar
- * changes to apic_send_ipi().
- */
-void
-apic_common_send_ipi(int cpun, int ipl)
-{
- int vector;
- ulong_t flag;
- int mode = apic_local_mode();
-
- if (mode == LOCAL_X2APIC) {
- x2apic_send_ipi(cpun, ipl);
- return;
- }
-
- ASSERT(mode == LOCAL_APIC);
-
- vector = apic_resv_vector[ipl];
- ASSERT((vector >= APIC_BASE_VECT) && (vector <= APIC_SPUR_INTR));
- flag = intr_clear();
- while (local_apic_regs_ops.apic_read(APIC_INT_CMD1) & AV_PENDING)
- apic_ret();
- local_apic_regs_ops.apic_write_int_cmd(apic_cpus[cpun].aci_local_id,
- vector);
- intr_restore(flag);
-}
diff --git a/usr/src/uts/i86pc/sys/apic.h b/usr/src/uts/i86pc/sys/apic.h
index 11ae48340a..828ef5b20d 100644
--- a/usr/src/uts/i86pc/sys/apic.h
+++ b/usr/src/uts/i86pc/sys/apic.h
@@ -20,8 +20,8 @@
*/
/*
* Copyright (c) 1993, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2017 Joyent, Inc.
*/
-
/*
* Copyright (c) 2010, Intel Corporation.
* All rights reserved.
@@ -117,6 +117,9 @@ typedef enum apic_mode {
#define APIC_SVR_SUPPRESS_BROADCAST_EOI 0x1000
#define APIC_DIRECTED_EOI_BIT 0x1000000
+/* x2APIC enable bit in REG_APIC_BASE_MSR */
+#define X2APIC_ENABLE_BIT 10
+
/* IRR register */
#define APIC_IRR_REG 0x80
@@ -867,6 +870,7 @@ extern int apic_sci_vect;
extern int apic_hpet_vect;
extern uchar_t apic_ipls[];
extern apic_reg_ops_t *apic_reg_ops;
+extern apic_reg_ops_t local_apic_regs_ops;
extern apic_mode_t apic_mode;
extern void x2apic_update_psm();
extern void apic_change_ops();