From owner-svn-src-head@FreeBSD.ORG Sat Mar 14 00:30:43 2015 Return-Path: Delivered-To: svn-src-head@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id F0996B3; Sat, 14 Mar 2015 00:30:42 +0000 (UTC) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id DBD01DE1; Sat, 14 Mar 2015 00:30:42 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.9/8.14.9) with ESMTP id t2E0UgX7003600; Sat, 14 Mar 2015 00:30:42 GMT (envelope-from neel@FreeBSD.org) Received: (from neel@localhost) by svn.freebsd.org (8.14.9/8.14.9/Submit) id t2E0Ugpf003597; Sat, 14 Mar 2015 00:30:42 GMT (envelope-from neel@FreeBSD.org) Message-Id: <201503140030.t2E0Ugpf003597@svn.freebsd.org> X-Authentication-Warning: svn.freebsd.org: neel set sender to neel@FreeBSD.org using -f From: Neel Natu Date: Sat, 14 Mar 2015 00:30:42 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r279970 - in head/sys/x86: include x86 xen X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.18-1 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 14 Mar 2015 00:30:43 -0000 Author: neel Date: Sat Mar 14 00:30:41 2015 New Revision: 279970 URL: https://svnweb.freebsd.org/changeset/base/279970 Log: Add x86 specific APIs 'lapic_ipi_alloc()' and 'lapic_ipi_free()' to allow IPI vectors to be dynamically allocated. This allows kernel modules like vmm.ko to allocate unique IPI slots when loaded (as opposed to hard allocating one or more vectors). Also, reorganize the fixed IPI vectors to create a contiguous space for dynamic IPI allocation. Reviewed by: kib, jhb Differential Revision: https://reviews.freebsd.org/D2042 Modified: head/sys/x86/include/apicvar.h head/sys/x86/x86/local_apic.c head/sys/x86/xen/xen_apic.c Modified: head/sys/x86/include/apicvar.h ============================================================================== --- head/sys/x86/include/apicvar.h Sat Mar 14 00:02:53 2015 (r279969) +++ head/sys/x86/include/apicvar.h Sat Mar 14 00:30:41 2015 (r279970) @@ -111,11 +111,8 @@ #define IPI_INVLPG (APIC_IPI_INTS + 2) #define IPI_INVLRNG (APIC_IPI_INTS + 3) #define IPI_INVLCACHE (APIC_IPI_INTS + 4) -#ifdef __i386__ -#define IPI_LAZYPMAP (APIC_IPI_INTS + 5) /* Lazy pmap release. */ -#endif /* Vector to handle bitmap based IPIs */ -#define IPI_BITMAP_VECTOR (APIC_IPI_INTS + 6) +#define IPI_BITMAP_VECTOR (APIC_IPI_INTS + 5) /* IPIs handled by IPI_BITMAP_VECTOR */ #define IPI_AST 0 /* Generate software trap. */ @@ -124,8 +121,15 @@ #define IPI_BITMAP_LAST IPI_HARDCLOCK #define IPI_IS_BITMAPED(x) ((x) <= IPI_BITMAP_LAST) -#define IPI_STOP (APIC_IPI_INTS + 7) /* Stop CPU until restarted. */ -#define IPI_SUSPEND (APIC_IPI_INTS + 8) /* Suspend CPU until restarted. */ +#define IPI_STOP (APIC_IPI_INTS + 6) /* Stop CPU until restarted. */ +#define IPI_SUSPEND (APIC_IPI_INTS + 7) /* Suspend CPU until restarted. */ +#ifdef __i386__ +#define IPI_LAZYPMAP (APIC_IPI_INTS + 8) /* Lazy pmap release. */ +#define IPI_DYN_FIRST (APIC_IPI_INTS + 9) +#else +#define IPI_DYN_FIRST (APIC_IPI_INTS + 8) +#endif +#define IPI_DYN_LAST (254) /* IPIs allocated at runtime */ /* * IPI_STOP_HARD does not need to occupy a slot in the IPI vector space since @@ -224,6 +228,8 @@ struct apic_ops { void (*ipi_raw)(register_t, u_int); void (*ipi_vectored)(u_int, int); int (*ipi_wait)(int); + int (*ipi_alloc)(inthand_t *ipifunc); + void (*ipi_free)(int vector); /* LVT */ int (*set_lvt_mask)(u_int, u_int, u_char); @@ -397,6 +403,20 @@ lapic_ipi_wait(int delay) } static inline int +lapic_ipi_alloc(inthand_t *ipifunc) +{ + + return (apic_ops.ipi_alloc(ipifunc)); +} + +static inline void +lapic_ipi_free(int vector) +{ + + return (apic_ops.ipi_free(vector)); +} + +static inline int lapic_set_lvt_mask(u_int apic_id, u_int lvt, u_char masked) { Modified: head/sys/x86/x86/local_apic.c ============================================================================== --- head/sys/x86/x86/local_apic.c Sat Mar 14 00:02:53 2015 (r279969) +++ head/sys/x86/x86/local_apic.c Sat Mar 14 00:30:41 2015 (r279970) @@ -303,6 +303,8 @@ static int native_lapic_set_lvt_polarit enum intr_polarity pol); static int native_lapic_set_lvt_triggermode(u_int apic_id, u_int lvt, enum intr_trigger trigger); +static int native_lapic_ipi_alloc(inthand_t *ipifunc); +static void native_lapic_ipi_free(int vector); struct apic_ops apic_ops = { .create = native_lapic_create, @@ -329,6 +331,8 @@ struct apic_ops apic_ops = { .ipi_raw = native_lapic_ipi_raw, .ipi_vectored = native_lapic_ipi_vectored, .ipi_wait = native_lapic_ipi_wait, + .ipi_alloc = native_lapic_ipi_alloc, + .ipi_free = native_lapic_ipi_free, #endif .set_lvt_mask = native_lapic_set_lvt_mask, .set_lvt_mode = native_lapic_set_lvt_mode, @@ -1761,4 +1765,60 @@ native_lapic_ipi_vectored(u_int vector, } #endif /* DETECT_DEADLOCK */ } + +/* + * Since the IDT is shared by all CPUs the IPI slot update needs to be globally + * visible. + * + * Consider the case where an IPI is generated immediately after allocation: + * vector = lapic_ipi_alloc(ipifunc); + * ipi_selected(other_cpus, vector); + * + * In xAPIC mode a write to ICR_LO has serializing semantics because the + * APIC page is mapped as an uncached region. In x2APIC mode there is an + * explicit 'mfence' before the ICR MSR is written. Therefore in both cases + * the IDT slot update is globally visible before the IPI is delivered. + */ +static int +native_lapic_ipi_alloc(inthand_t *ipifunc) +{ + struct gate_descriptor *ip; + long func; + int idx, vector; + + KASSERT(ipifunc != &IDTVEC(rsvd), ("invalid ipifunc %p", ipifunc)); + + vector = -1; + mtx_lock_spin(&icu_lock); + for (idx = IPI_DYN_FIRST; idx <= IPI_DYN_LAST; idx++) { + ip = &idt[idx]; + func = (ip->gd_hioffset << 16) | ip->gd_looffset; + if (func == (uintptr_t)&IDTVEC(rsvd)) { + vector = idx; + setidt(vector, ipifunc, SDT_APIC, SEL_KPL, GSEL_APIC); + break; + } + } + mtx_unlock_spin(&icu_lock); + return (vector); +} + +static void +native_lapic_ipi_free(int vector) +{ + struct gate_descriptor *ip; + long func; + + KASSERT(vector >= IPI_DYN_FIRST && vector <= IPI_DYN_LAST, + ("%s: invalid vector %d", __func__, vector)); + + mtx_lock_spin(&icu_lock); + ip = &idt[vector]; + func = (ip->gd_hioffset << 16) | ip->gd_looffset; + KASSERT(func != (uintptr_t)&IDTVEC(rsvd), + ("invalid idtfunc %#lx", func)); + setidt(vector, &IDTVEC(rsvd), SDT_APICT, SEL_KPL, GSEL_APIC); + mtx_unlock_spin(&icu_lock); +} + #endif /* SMP */ Modified: head/sys/x86/xen/xen_apic.c ============================================================================== --- head/sys/x86/xen/xen_apic.c Sat Mar 14 00:02:53 2015 (r279969) +++ head/sys/x86/xen/xen_apic.c Sat Mar 14 00:30:41 2015 (r279970) @@ -311,7 +311,22 @@ xen_pv_lapic_ipi_wait(int delay) XEN_APIC_UNSUPPORTED; return (0); } -#endif + +static int +xen_pv_lapic_ipi_alloc(inthand_t *ipifunc) +{ + + XEN_APIC_UNSUPPORTED; + return (-1); +} + +static void +xen_pv_lapic_ipi_free(int vector) +{ + + XEN_APIC_UNSUPPORTED; +} +#endif /* SMP */ static int xen_pv_lapic_set_lvt_mask(u_int apic_id, u_int lvt, u_char masked) @@ -372,6 +387,8 @@ struct apic_ops xen_apic_ops = { .ipi_raw = xen_pv_lapic_ipi_raw, .ipi_vectored = xen_pv_lapic_ipi_vectored, .ipi_wait = xen_pv_lapic_ipi_wait, + .ipi_alloc = xen_pv_lapic_ipi_alloc, + .ipi_free = xen_pv_lapic_ipi_free, #endif .set_lvt_mask = xen_pv_lapic_set_lvt_mask, .set_lvt_mode = xen_pv_lapic_set_lvt_mode,