From owner-svn-src-projects@FreeBSD.ORG Sun Dec 16 00:57:15 2012 Return-Path: Delivered-To: svn-src-projects@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [69.147.83.52]) by hub.freebsd.org (Postfix) with ESMTP id 92A8A1F7; Sun, 16 Dec 2012 00:57:15 +0000 (UTC) (envelope-from neel@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) by mx1.freebsd.org (Postfix) with ESMTP id 794FB8FC14; Sun, 16 Dec 2012 00:57:15 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.5/8.14.5) with ESMTP id qBG0vFm1069675; Sun, 16 Dec 2012 00:57:15 GMT (envelope-from neel@svn.freebsd.org) Received: (from neel@localhost) by svn.freebsd.org (8.14.5/8.14.5/Submit) id qBG0vEqp069672; Sun, 16 Dec 2012 00:57:14 GMT (envelope-from neel@svn.freebsd.org) Message-Id: <201212160057.qBG0vEqp069672@svn.freebsd.org> From: Neel Natu Date: Sun, 16 Dec 2012 00:57:14 +0000 (UTC) To: src-committers@freebsd.org, svn-src-projects@freebsd.org Subject: svn commit: r244282 - in projects/bhyve/sys: amd64/amd64 amd64/include x86/x86 X-SVN-Group: projects MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-projects@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: "SVN commit messages for the src " projects" tree" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 16 Dec 2012 00:57:15 -0000 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 #include #include +#include #include #include #include #include +#include #include #include #include @@ -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; }