svn commit: r244282 - in projects/bhyve/sys: amd64/amd64 amd64/include x86/x86
Neel Natu
neel at FreeBSD.org
Sun Dec 16 00:57:15 UTC 2012
Author: neel
Date: Sun Dec 16 00:57:14 2012
New Revision: 244282
URL: http://svnweb.freebsd.org/changeset/base/244282
Log:
Prefer x2apic mode when running inside a virtual machine.
Provide a tunable 'machdep.x2apic_desired' to let the administrator override
the default behavior.
Provide a read-only sysctl 'machdep.x2apic' to let the administrator know
whether the kernel is using x2apic or legacy mmio to access local apic.
Tested with Parallels Desktop 8 and bhyve hypervisors.
Also tested running on bare metal Intel Xeon E5-2658.
Obtained from: NetApp
Discussed with: jhb, attilio, avg, grehan
Modified:
projects/bhyve/sys/amd64/amd64/mp_machdep.c
projects/bhyve/sys/amd64/include/apicvar.h
projects/bhyve/sys/x86/x86/local_apic.c
Modified: projects/bhyve/sys/amd64/amd64/mp_machdep.c
==============================================================================
--- projects/bhyve/sys/amd64/amd64/mp_machdep.c Sun Dec 16 00:20:16 2012 (r244281)
+++ projects/bhyve/sys/amd64/amd64/mp_machdep.c Sun Dec 16 00:57:14 2012 (r244282)
@@ -708,6 +708,8 @@ init_secondary(void)
wrmsr(MSR_STAR, msr);
wrmsr(MSR_SF_MASK, PSL_NT|PSL_T|PSL_I|PSL_C|PSL_D);
+ lapic_init_ap();
+
/* Disable local APIC just to be sure. */
lapic_disable();
Modified: projects/bhyve/sys/amd64/include/apicvar.h
==============================================================================
--- projects/bhyve/sys/amd64/include/apicvar.h Sun Dec 16 00:20:16 2012 (r244281)
+++ projects/bhyve/sys/amd64/include/apicvar.h Sun Dec 16 00:57:14 2012 (r244282)
@@ -209,6 +209,7 @@ int lapic_enable_pmc(void);
void lapic_eoi(void);
int lapic_id(void);
void lapic_init(vm_paddr_t addr);
+void lapic_init_ap(void);
int lapic_intr_pending(u_int vector);
void lapic_ipi_raw(register_t icrlo, u_int dest);
void lapic_ipi_vectored(u_int vector, int dest);
Modified: projects/bhyve/sys/x86/x86/local_apic.c
==============================================================================
--- projects/bhyve/sys/x86/x86/local_apic.c Sun Dec 16 00:20:16 2012 (r244281)
+++ projects/bhyve/sys/x86/x86/local_apic.c Sun Dec 16 00:57:14 2012 (r244282)
@@ -50,12 +50,14 @@ __FBSDID("$FreeBSD$");
#include <sys/proc.h>
#include <sys/sched.h>
#include <sys/smp.h>
+#include <sys/sysctl.h>
#include <sys/timeet.h>
#include <vm/vm.h>
#include <vm/pmap.h>
#include <x86/apicreg.h>
+#include <machine/atomic.h>
#include <machine/cpu.h>
#include <machine/cputypes.h>
#include <machine/frame.h>
@@ -158,7 +160,15 @@ volatile lapic_t *lapic;
vm_paddr_t lapic_paddr;
static u_long lapic_timer_divisor;
static struct eventtimer lapic_et;
+
static int x2apic;
+SYSCTL_INT(_machdep, OID_AUTO, x2apic, CTLFLAG_RD, &x2apic, 0, "x2apic mode");
+
+static int x2apic_desired = -1; /* enable only if running in a VM */
+TUNABLE_INT("machdep.x2apic_desired", &x2apic_desired);
+SYSCTL_INT(_machdep, OID_AUTO, x2apic_desired, CTLFLAG_RDTUN,
+ &x2apic_desired, 0,
+ "0 (disable), 1 (enable), -1 (leave it up to the kernel)");
static void lapic_enable(void);
static void lapic_resume(struct pic *pic);
@@ -247,6 +257,17 @@ lvt_mode(struct lapic *la, u_int pin, ui
return (value);
}
+static void
+x2apic_init(void)
+{
+ uint64_t apic_base;
+
+ apic_base = rdmsr(MSR_APICBASE);
+
+ if ((apic_base & APICBASE_X2APIC) == 0)
+ wrmsr(MSR_APICBASE, apic_base | APICBASE_X2APIC);
+}
+
/*
* Map the local APIC and setup necessary interrupt vectors.
*/
@@ -256,9 +277,21 @@ lapic_init(vm_paddr_t addr)
u_int regs[4];
int i, arat;
- if ((cpu_feature2 & CPUID2_X2APIC) != 0 &&
- (rdmsr(MSR_APICBASE) & APICBASE_X2APIC) != 0) {
- x2apic = 1;
+ if ((cpu_feature2 & CPUID2_X2APIC) != 0) {
+ if (rdmsr(MSR_APICBASE) & APICBASE_X2APIC)
+ x2apic = 1;
+ else if (x2apic_desired != 0) {
+ /*
+ * The default behavior is to enable x2apic only if
+ * the kernel is executing inside a virtual machine.
+ */
+ if (vm_guest != VM_GUEST_NO || x2apic_desired == 1)
+ x2apic = 1;
+ }
+ }
+
+ if (x2apic) {
+ x2apic_init();
if (bootverbose)
printf("Local APIC access using x2APIC MSRs\n");
} else {
@@ -317,6 +350,14 @@ lapic_init(vm_paddr_t addr)
}
}
+void
+lapic_init_ap(void)
+{
+
+ if (x2apic)
+ x2apic_init();
+}
+
/*
* Create a local APIC instance.
*/
@@ -934,9 +975,26 @@ static void
lapic_set_icr(uint64_t value)
{
- if (x2apic)
+ /*
+ * Access to x2apic MSR registers is not a serializing condition.
+ *
+ * A number of IPI handlers (e.g. rendezvous, tlb shootdown)
+ * depend on shared state in memory between the cpu that
+ * originated the IPI and the cpus that are the target.
+ *
+ * Insert a memory barrier to ensure that changes to memory
+ * are globally visible to the other cpus.
+ */
+ if (x2apic) {
+ /*
+ * XXX
+ * Intel's architecture spec seems to suggest that an
+ * "sfence" should be sufficient here but empirically
+ * an "mfence" is required to do the job.
+ */
+ mb();
wrmsr(MSR_APIC_ICR, value);
- else {
+ } else {
lapic->icr_hi = value >> 32;
lapic->icr_lo = value;
}
More information about the svn-src-projects
mailing list