summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/amd64/amd64/mp_machdep.c10
-rw-r--r--sys/amd64/amd64/pmap.c24
-rw-r--r--sys/amd64/include/cpu.h11
-rw-r--r--sys/amd64/include/cpufunc.h28
-rw-r--r--sys/amd64/include/pcpu.h9
-rw-r--r--sys/i386/i386/mp_machdep.c10
-rw-r--r--sys/i386/include/cpu.h11
-rw-r--r--sys/i386/include/pcpu.h9
-rw-r--r--sys/i386/include/smp.h5
-rw-r--r--sys/i386/xen/mp_machdep.c113
-rw-r--r--sys/x86/xen/hvm.c447
-rw-r--r--sys/x86/xen/xen_intr.c2
-rw-r--r--sys/xen/xen_intr.h11
13 files changed, 576 insertions, 114 deletions
diff --git a/sys/amd64/amd64/mp_machdep.c b/sys/amd64/amd64/mp_machdep.c
index 3addd43..0fdb668 100644
--- a/sys/amd64/amd64/mp_machdep.c
+++ b/sys/amd64/amd64/mp_machdep.c
@@ -69,6 +69,7 @@ __FBSDID("$FreeBSD$");
#include <machine/smp.h>
#include <machine/specialreg.h>
#include <machine/tss.h>
+#include <machine/cpu.h>
#ifdef XENHVM
#include <xen/hvm.h>
@@ -125,6 +126,11 @@ u_long *ipi_rendezvous_counts[MAXCPU];
static u_long *ipi_hardclock_counts[MAXCPU];
#endif
+/* Default cpu_ops implementation. */
+struct cpu_ops cpu_ops = {
+ .ipi_vectored = lapic_ipi_vectored
+};
+
extern inthand_t IDTVEC(fast_syscall), IDTVEC(fast_syscall32);
extern int pmap_pcid_enabled;
@@ -1125,7 +1131,7 @@ ipi_send_cpu(int cpu, u_int ipi)
if (old_pending)
return;
}
- lapic_ipi_vectored(ipi, cpu_apic_ids[cpu]);
+ cpu_ops.ipi_vectored(ipi, cpu_apic_ids[cpu]);
}
/*
@@ -1395,7 +1401,7 @@ ipi_all_but_self(u_int ipi)
CPU_OR_ATOMIC(&ipi_nmi_pending, &other_cpus);
CTR2(KTR_SMP, "%s: ipi: %x", __func__, ipi);
- lapic_ipi_vectored(ipi, APIC_IPI_DEST_OTHERS);
+ cpu_ops.ipi_vectored(ipi, APIC_IPI_DEST_OTHERS);
}
int
diff --git a/sys/amd64/amd64/pmap.c b/sys/amd64/amd64/pmap.c
index 8940d4a..10d4184 100644
--- a/sys/amd64/amd64/pmap.c
+++ b/sys/amd64/amd64/pmap.c
@@ -254,30 +254,6 @@ SYSCTL_INT(_vm_pmap, OID_AUTO, pcid_enabled, CTLFLAG_RDTUN, &pmap_pcid_enabled,
0, "Is TLB Context ID enabled ?");
int invpcid_works = 0;
-/*
- * Perform the guaranteed invalidation of all TLB entries. This
- * includes the global entries, and entries in all PCIDs, not only the
- * current context. The function works both on non-PCID CPUs and CPUs
- * with the PCID turned off or on. See IA-32 SDM Vol. 3a 4.10.4.1
- * Operations that Invalidate TLBs and Paging-Structure Caches.
- */
-static __inline void
-invltlb_globpcid(void)
-{
- uint64_t cr4;
-
- cr4 = rcr4();
- load_cr4(cr4 & ~CR4_PGE);
- /*
- * Although preemption at this point could be detrimental to
- * performance, it would not lead to an error. PG_G is simply
- * ignored if CR4.PGE is clear. Moreover, in case this block
- * is re-entered, the load_cr4() either above or below will
- * modify CR4.PGE flushing the TLB.
- */
- load_cr4(cr4 | CR4_PGE);
-}
-
static int
pmap_pcid_save_cnt_proc(SYSCTL_HANDLER_ARGS)
{
diff --git a/sys/amd64/include/cpu.h b/sys/amd64/include/cpu.h
index 1c2871f..5b994e1 100644
--- a/sys/amd64/include/cpu.h
+++ b/sys/amd64/include/cpu.h
@@ -54,6 +54,17 @@
#define TRAPF_PC(framep) ((framep)->tf_rip)
#ifdef _KERNEL
+/*
+ * Struct containing pointers to CPU management functions whose
+ * implementation is run time selectable. Selection can be made,
+ * for example, based on detection of a particular CPU variant or
+ * hypervisor environment.
+ */
+struct cpu_ops {
+ void (*ipi_vectored)(u_int, int);
+};
+
+extern struct cpu_ops cpu_ops;
extern char btext[];
extern char etext[];
diff --git a/sys/amd64/include/cpufunc.h b/sys/amd64/include/cpufunc.h
index 3d381c6..5f8197b 100644
--- a/sys/amd64/include/cpufunc.h
+++ b/sys/amd64/include/cpufunc.h
@@ -461,6 +461,34 @@ invltlb(void)
load_cr3(rcr3());
}
+#ifndef CR4_PGE
+#define CR4_PGE 0x00000080 /* Page global enable */
+#endif
+
+/*
+ * Perform the guaranteed invalidation of all TLB entries. This
+ * includes the global entries, and entries in all PCIDs, not only the
+ * current context. The function works both on non-PCID CPUs and CPUs
+ * with the PCID turned off or on. See IA-32 SDM Vol. 3a 4.10.4.1
+ * Operations that Invalidate TLBs and Paging-Structure Caches.
+ */
+static __inline void
+invltlb_globpcid(void)
+{
+ uint64_t cr4;
+
+ cr4 = rcr4();
+ load_cr4(cr4 & ~CR4_PGE);
+ /*
+ * Although preemption at this point could be detrimental to
+ * performance, it would not lead to an error. PG_G is simply
+ * ignored if CR4.PGE is clear. Moreover, in case this block
+ * is re-entered, the load_cr4() either above or below will
+ * modify CR4.PGE flushing the TLB.
+ */
+ load_cr4(cr4 | CR4_PGE);
+}
+
/*
* TLB flush for an individual page (even if it has PG_G).
* Only works on 486+ CPUs (i386 does not have PG_G).
diff --git a/sys/amd64/include/pcpu.h b/sys/amd64/include/pcpu.h
index 387df1a..3d51512 100644
--- a/sys/amd64/include/pcpu.h
+++ b/sys/amd64/include/pcpu.h
@@ -33,15 +33,6 @@
#error "sys/cdefs.h is a prerequisite for this file"
#endif
-#if defined(XEN) || defined(XENHVM)
-#ifndef NR_VIRQS
-#define NR_VIRQS 24
-#endif
-#ifndef NR_IPIS
-#define NR_IPIS 2
-#endif
-#endif
-
/*
* The SMP parts are setup in pmap.c and locore.s for the BSP, and
* mp_machdep.c sets up the data for the AP's to "see" when they awake.
diff --git a/sys/i386/i386/mp_machdep.c b/sys/i386/i386/mp_machdep.c
index 479168b..60b36a2 100644
--- a/sys/i386/i386/mp_machdep.c
+++ b/sys/i386/i386/mp_machdep.c
@@ -81,6 +81,7 @@ __FBSDID("$FreeBSD$");
#include <machine/psl.h>
#include <machine/smp.h>
#include <machine/specialreg.h>
+#include <machine/cpu.h>
#ifdef XENHVM
#include <xen/hvm.h>
@@ -170,6 +171,11 @@ u_long *ipi_lazypmap_counts[MAXCPU];
static u_long *ipi_hardclock_counts[MAXCPU];
#endif
+/* Default cpu_ops implementation. */
+struct cpu_ops cpu_ops = {
+ .ipi_vectored = lapic_ipi_vectored
+};
+
/*
* Local data and functions.
*/
@@ -1209,7 +1215,7 @@ ipi_send_cpu(int cpu, u_int ipi)
if (old_pending)
return;
}
- lapic_ipi_vectored(ipi, cpu_apic_ids[cpu]);
+ cpu_ops.ipi_vectored(ipi, cpu_apic_ids[cpu]);
}
/*
@@ -1460,7 +1466,7 @@ ipi_all_but_self(u_int ipi)
CPU_OR_ATOMIC(&ipi_nmi_pending, &other_cpus);
CTR2(KTR_SMP, "%s: ipi: %x", __func__, ipi);
- lapic_ipi_vectored(ipi, APIC_IPI_DEST_OTHERS);
+ cpu_ops.ipi_vectored(ipi, APIC_IPI_DEST_OTHERS);
}
int
diff --git a/sys/i386/include/cpu.h b/sys/i386/include/cpu.h
index 5bc9f5c..9655a15 100644
--- a/sys/i386/include/cpu.h
+++ b/sys/i386/include/cpu.h
@@ -54,6 +54,17 @@
#define TRAPF_PC(framep) ((framep)->tf_eip)
#ifdef _KERNEL
+/*
+ * Struct containing pointers to CPU management functions whose
+ * implementation is run time selectable. Selection can be made,
+ * for example, based on detection of a particular CPU variant or
+ * hypervisor environment.
+ */
+struct cpu_ops {
+ void (*ipi_vectored)(u_int, int);
+};
+
+extern struct cpu_ops cpu_ops;
extern char btext[];
extern char etext[];
diff --git a/sys/i386/include/pcpu.h b/sys/i386/include/pcpu.h
index 3a684bf..60e50f8 100644
--- a/sys/i386/include/pcpu.h
+++ b/sys/i386/include/pcpu.h
@@ -44,15 +44,6 @@
* other processors"
*/
-#if defined(XEN) || defined(XENHVM)
-#ifndef NR_VIRQS
-#define NR_VIRQS 24
-#endif
-#ifndef NR_IPIS
-#define NR_IPIS 2
-#endif
-#endif
-
#if defined(XEN)
/* These are peridically updated in shared_info, and then copied here. */
diff --git a/sys/i386/include/smp.h b/sys/i386/include/smp.h
index 7c11820..43dad10 100644
--- a/sys/i386/include/smp.h
+++ b/sys/i386/include/smp.h
@@ -84,11 +84,6 @@ void smp_masked_invltlb(cpuset_t mask);
#ifdef XEN
void ipi_to_irq_init(void);
-
-#define RESCHEDULE_VECTOR 0
-#define CALL_FUNCTION_VECTOR 1
-#define NR_IPIS 2
-
#endif
#endif /* !LOCORE */
#endif /* SMP */
diff --git a/sys/i386/xen/mp_machdep.c b/sys/i386/xen/mp_machdep.c
index 7ac1dbb..d6eb35b 100644
--- a/sys/i386/xen/mp_machdep.c
+++ b/sys/i386/xen/mp_machdep.c
@@ -99,25 +99,37 @@ extern void failsafe_callback(void);
extern void pmap_lazyfix_action(void);
/*--------------------------- Forward Declarations ---------------------------*/
-static void assign_cpu_ids(void);
-static void set_interrupt_apic_ids(void);
-static int start_all_aps(void);
-static int start_ap(int apic_id);
-static void release_aps(void *dummy);
+static driver_filter_t smp_reschedule_interrupt;
+static driver_filter_t smp_call_function_interrupt;
+static void assign_cpu_ids(void);
+static void set_interrupt_apic_ids(void);
+static int start_all_aps(void);
+static int start_ap(int apic_id);
+static void release_aps(void *dummy);
+
+/*---------------------------------- Macros ----------------------------------*/
+#define IPI_TO_IDX(ipi) ((ipi) - APIC_IPI_INTS)
/*-------------------------------- Local Types -------------------------------*/
typedef void call_data_func_t(uintptr_t , uintptr_t);
-/*
- * Store data from cpu_add() until later in the boot when we actually setup
- * the APs.
- */
struct cpu_info {
int cpu_present:1;
int cpu_bsp:1;
int cpu_disabled:1;
};
+struct xen_ipi_handler
+{
+ driver_filter_t *filter;
+ const char *description;
+};
+
+enum {
+ RESCHEDULE_VECTOR,
+ CALL_FUNCTION_VECTOR,
+};
+
/*-------------------------------- Global Data -------------------------------*/
static u_int hyperthreading_cpus;
static cpuset_t hyperthreading_cpus_mask;
@@ -161,8 +173,14 @@ static volatile u_int cpu_ipi_pending[MAXCPU];
static int cpu_logical;
static int cpu_cores;
+static const struct xen_ipi_handler xen_ipis[] =
+{
+ [RESCHEDULE_VECTOR] = { smp_reschedule_interrupt, "resched" },
+ [CALL_FUNCTION_VECTOR] = { smp_call_function_interrupt,"callfunc" }
+};
+
/*------------------------------- Per-CPU Data -------------------------------*/
-DPCPU_DEFINE(xen_intr_handle_t, ipi_port[NR_IPIS]);
+DPCPU_DEFINE(xen_intr_handle_t, ipi_handle[nitems(xen_ipis)]);
DPCPU_DEFINE(struct vcpu_info *, vcpu_info);
/*------------------------------ Implementation ------------------------------*/
@@ -362,7 +380,7 @@ iv_lazypmap(uintptr_t a, uintptr_t b)
/*
* These start from "IPI offset" APIC_IPI_INTS
*/
-static call_data_func_t *ipi_vectors[] =
+static call_data_func_t *ipi_vectors[6] =
{
iv_rendezvous,
iv_invltlb,
@@ -427,7 +445,7 @@ smp_call_function_interrupt(void *unused)
call_data->func_id > IPI_BITMAP_VECTOR)
panic("invalid function id %u", call_data->func_id);
- func = ipi_vectors[call_data->func_id - APIC_IPI_INTS];
+ func = ipi_vectors[IPI_TO_IDX(call_data->func_id)];
/*
* Notify initiating CPU that I've grabbed the data and am
* about to execute the function
@@ -473,44 +491,43 @@ cpu_mp_announce(void)
static int
xen_smp_cpu_init(unsigned int cpu)
{
- int rc;
- xen_intr_handle_t irq_handle;
+ xen_intr_handle_t *ipi_handle;
+ const struct xen_ipi_handler *ipi;
+ int idx, rc;
- DPCPU_ID_SET(cpu, ipi_port[RESCHEDULE_VECTOR], NULL);
- DPCPU_ID_SET(cpu, ipi_port[CALL_FUNCTION_VECTOR], NULL);
+ ipi_handle = DPCPU_ID_GET(cpu, ipi_handle);
+ for (ipi = xen_ipis, idx = 0; idx < nitems(xen_ipis); ipi++, idx++) {
- /*
- * The PCPU variable pc_device is not initialized on i386 PV,
- * so we have to use the root_bus device in order to setup
- * the IPIs.
- */
- rc = xen_intr_bind_ipi(root_bus, RESCHEDULE_VECTOR,
- cpu, smp_reschedule_interrupt, INTR_TYPE_TTY, &irq_handle);
- if (rc < 0)
- goto fail;
- xen_intr_describe(irq_handle, "resched%u", cpu);
- DPCPU_ID_SET(cpu, ipi_port[RESCHEDULE_VECTOR], irq_handle);
-
- printf("[XEN] IPI cpu=%d port=%d vector=RESCHEDULE_VECTOR (%d)\n",
- cpu, xen_intr_port(irq_handle), RESCHEDULE_VECTOR);
-
- rc = xen_intr_bind_ipi(root_bus, CALL_FUNCTION_VECTOR,
- cpu, smp_call_function_interrupt, INTR_TYPE_TTY, &irq_handle);
- if (rc < 0)
- goto fail;
- xen_intr_describe(irq_handle, "callfunc%u", cpu);
- DPCPU_ID_SET(cpu, ipi_port[CALL_FUNCTION_VECTOR], irq_handle);
-
- printf("[XEN] IPI cpu=%d port=%d vector=CALL_FUNCTION_VECTOR (%d)\n",
- cpu, xen_intr_port(irq_handle), CALL_FUNCTION_VECTOR);
+ /*
+ * The PCPU variable pc_device is not initialized on i386 PV,
+ * so we have to use the root_bus device in order to setup
+ * the IPIs.
+ */
+ rc = xen_intr_alloc_and_bind_ipi(root_bus, cpu,
+ ipi->filter, INTR_TYPE_TTY, &ipi_handle[idx]);
+ if (rc != 0) {
+ printf("Unable to allocate a XEN IPI port. "
+ "Error %d\n", rc);
+ break;
+ }
+ xen_intr_describe(ipi_handle[idx], "%s", ipi->description);
+ }
- return (0);
+ for (;idx < nitems(xen_ipis); idx++)
+ ipi_handle[idx] = NULL;
+
+ if (rc == 0)
+ return (0);
+
+ /* Either all are successfully mapped, or none at all. */
+ for (idx = 0; idx < nitems(xen_ipis); idx++) {
+ if (ipi_handle[idx] == NULL)
+ continue;
+
+ xen_intr_unbind(ipi_handle[idx]);
+ ipi_handle[idx] = NULL;
+ }
- fail:
- xen_intr_unbind(DPCPU_ID_GET(cpu, ipi_port[RESCHEDULE_VECTOR]));
- DPCPU_ID_SET(cpu, ipi_port[RESCHEDULE_VECTOR], NULL);
- xen_intr_unbind(DPCPU_ID_GET(cpu, ipi_port[CALL_FUNCTION_VECTOR]));
- DPCPU_ID_SET(cpu, ipi_port[CALL_FUNCTION_VECTOR], NULL);
return (rc);
}
@@ -980,8 +997,8 @@ start_ap(int apic_id)
static void
ipi_pcpu(int cpu, u_int ipi)
{
- KASSERT((ipi <= NR_IPIS), ("invalid IPI"));
- xen_intr_signal(DPCPU_ID_GET(cpu, ipi_port[ipi]));
+ KASSERT((ipi <= nitems(xen_ipis)), ("invalid IPI"));
+ xen_intr_signal(DPCPU_ID_GET(cpu, ipi_handle[ipi]));
}
/*
diff --git a/sys/x86/xen/hvm.c b/sys/x86/xen/hvm.c
index c689b47..0404fe9 100644
--- a/sys/x86/xen/hvm.c
+++ b/sys/x86/xen/hvm.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008 Citrix Systems, Inc.
+ * Copyright (c) 2008, 2013 Citrix Systems, Inc.
* Copyright (c) 2012 Spectra Logic Corporation
* All rights reserved.
*
@@ -33,9 +33,19 @@ __FBSDID("$FreeBSD$");
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/proc.h>
+#include <sys/smp.h>
+#include <sys/systm.h>
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
#include <dev/pci/pcivar.h>
+
#include <machine/cpufunc.h>
+#include <machine/cpu.h>
+#include <machine/smp.h>
+
+#include <x86/apicreg.h>
#include <xen/xen-os.h>
#include <xen/features.h>
@@ -44,30 +54,450 @@ __FBSDID("$FreeBSD$");
#include <xen/hvm.h>
#include <xen/xen_intr.h>
-#include <vm/vm.h>
-#include <vm/pmap.h>
-
#include <xen/interface/hvm/params.h>
#include <xen/interface/vcpu.h>
+/*--------------------------- Forward Declarations ---------------------------*/
+static driver_filter_t xen_smp_rendezvous_action;
+static driver_filter_t xen_invltlb;
+static driver_filter_t xen_invlpg;
+static driver_filter_t xen_invlrng;
+static driver_filter_t xen_invlcache;
+#ifdef __i386__
+static driver_filter_t xen_lazypmap;
+#endif
+static driver_filter_t xen_ipi_bitmap_handler;
+static driver_filter_t xen_cpustop_handler;
+static driver_filter_t xen_cpususpend_handler;
+static driver_filter_t xen_cpustophard_handler;
+
+/*---------------------------- Extern Declarations ---------------------------*/
+/* Variables used by mp_machdep to perform the MMU related IPIs */
+extern volatile int smp_tlb_wait;
+extern vm_offset_t smp_tlb_addr2;
+#ifdef __i386__
+extern vm_offset_t smp_tlb_addr1;
+#else
+extern struct invpcid_descr smp_tlb_invpcid;
+extern uint64_t pcid_cr3;
+extern int invpcid_works;
+extern int pmap_pcid_enabled;
+extern pmap_t smp_tlb_pmap;
+#endif
+
+#ifdef __i386__
+extern void pmap_lazyfix_action(void);
+#endif
+
+/*---------------------------------- Macros ----------------------------------*/
+#define IPI_TO_IDX(ipi) ((ipi) - APIC_IPI_INTS)
+
+/*-------------------------------- Local Types -------------------------------*/
+struct xen_ipi_handler
+{
+ driver_filter_t *filter;
+ const char *description;
+};
+
+/*-------------------------------- Global Data -------------------------------*/
+enum xen_domain_type xen_domain_type = XEN_NATIVE;
+
static MALLOC_DEFINE(M_XENHVM, "xen_hvm", "Xen HVM PV Support");
-DPCPU_DEFINE(struct vcpu_info, vcpu_local_info);
-DPCPU_DEFINE(struct vcpu_info *, vcpu_info);
+static struct xen_ipi_handler xen_ipis[] =
+{
+ [IPI_TO_IDX(IPI_RENDEZVOUS)] = { xen_smp_rendezvous_action, "r" },
+ [IPI_TO_IDX(IPI_INVLTLB)] = { xen_invltlb, "itlb"},
+ [IPI_TO_IDX(IPI_INVLPG)] = { xen_invlpg, "ipg" },
+ [IPI_TO_IDX(IPI_INVLRNG)] = { xen_invlrng, "irg" },
+ [IPI_TO_IDX(IPI_INVLCACHE)] = { xen_invlcache, "ic" },
+#ifdef __i386__
+ [IPI_TO_IDX(IPI_LAZYPMAP)] = { xen_lazypmap, "lp" },
+#endif
+ [IPI_TO_IDX(IPI_BITMAP_VECTOR)] = { xen_ipi_bitmap_handler, "b" },
+ [IPI_TO_IDX(IPI_STOP)] = { xen_cpustop_handler, "st" },
+ [IPI_TO_IDX(IPI_SUSPEND)] = { xen_cpususpend_handler, "sp" },
+ [IPI_TO_IDX(IPI_STOP_HARD)] = { xen_cpustophard_handler, "sth" },
+};
-/*-------------------------------- Global Data -------------------------------*/
/**
* If non-zero, the hypervisor has been configured to use a direct
* IDT event callback for interrupt injection.
*/
int xen_vector_callback_enabled;
+/*------------------------------- Per-CPU Data -------------------------------*/
+DPCPU_DEFINE(struct vcpu_info, vcpu_local_info);
+DPCPU_DEFINE(struct vcpu_info *, vcpu_info);
+DPCPU_DEFINE(xen_intr_handle_t, ipi_handle[nitems(xen_ipis)]);
+
/*------------------ Hypervisor Access Shared Memory Regions -----------------*/
/** Hypercall table accessed via HYPERVISOR_*_op() methods. */
char *hypercall_stubs;
shared_info_t *HYPERVISOR_shared_info;
-enum xen_domain_type xen_domain_type = XEN_NATIVE;
+/*---------------------------- XEN PV IPI Handlers ---------------------------*/
+/*
+ * This are C clones of the ASM functions found in apic_vector.s
+ */
+static int
+xen_ipi_bitmap_handler(void *arg)
+{
+ struct trapframe *frame;
+
+ frame = arg;
+ ipi_bitmap_handler(*frame);
+ return (FILTER_HANDLED);
+}
+
+static int
+xen_smp_rendezvous_action(void *arg)
+{
+#ifdef COUNT_IPIS
+ int cpu;
+
+ cpu = PCPU_GET(cpuid);
+ (*ipi_rendezvous_counts[cpu])++;
+#endif /* COUNT_IPIS */
+
+ smp_rendezvous_action();
+ return (FILTER_HANDLED);
+}
+
+static int
+xen_invltlb(void *arg)
+{
+#if defined(COUNT_XINVLTLB_HITS) || defined(COUNT_IPIS)
+ int cpu;
+
+ cpu = PCPU_GET(cpuid);
+#ifdef COUNT_XINVLTLB_HITS
+ xhits_gbl[cpu]++;
+#endif /* COUNT_XINVLTLB_HITS */
+#ifdef COUNT_IPIS
+ (*ipi_invltlb_counts[cpu])++;
+#endif /* COUNT_IPIS */
+#endif /* COUNT_XINVLTLB_HITS || COUNT_IPIS */
+
+ invltlb();
+ atomic_add_int(&smp_tlb_wait, 1);
+ return (FILTER_HANDLED);
+}
+
+#ifdef __amd64__
+static int
+xen_invltlb_pcid(void *arg)
+{
+ uint64_t cr3;
+#if defined(COUNT_XINVLTLB_HITS) || defined(COUNT_IPIS)
+ int cpu;
+
+ cpu = PCPU_GET(cpuid);
+#ifdef COUNT_XINVLTLB_HITS
+ xhits_gbl[cpu]++;
+#endif /* COUNT_XINVLTLB_HITS */
+#ifdef COUNT_IPIS
+ (*ipi_invltlb_counts[cpu])++;
+#endif /* COUNT_IPIS */
+#endif /* COUNT_XINVLTLB_HITS || COUNT_IPIS */
+
+ cr3 = rcr3();
+ if (smp_tlb_invpcid.pcid != (uint64_t)-1 &&
+ smp_tlb_invpcid.pcid != 0) {
+
+ if (invpcid_works) {
+ invpcid(&smp_tlb_invpcid, INVPCID_CTX);
+ } else {
+ /* Otherwise reload %cr3 twice. */
+ if (cr3 != pcid_cr3) {
+ load_cr3(pcid_cr3);
+ cr3 |= CR3_PCID_SAVE;
+ }
+ load_cr3(cr3);
+ }
+ } else {
+ invltlb_globpcid();
+ }
+ if (smp_tlb_pmap != NULL)
+ CPU_CLR_ATOMIC(PCPU_GET(cpuid), &smp_tlb_pmap->pm_save);
+
+ atomic_add_int(&smp_tlb_wait, 1);
+ return (FILTER_HANDLED);
+}
+#endif
+
+static int
+xen_invlpg(void *arg)
+{
+#if defined(COUNT_XINVLTLB_HITS) || defined(COUNT_IPIS)
+ int cpu;
+
+ cpu = PCPU_GET(cpuid);
+#ifdef COUNT_XINVLTLB_HITS
+ xhits_pg[cpu]++;
+#endif /* COUNT_XINVLTLB_HITS */
+#ifdef COUNT_IPIS
+ (*ipi_invlpg_counts[cpu])++;
+#endif /* COUNT_IPIS */
+#endif /* COUNT_XINVLTLB_HITS || COUNT_IPIS */
+
+#ifdef __i386__
+ invlpg(smp_tlb_addr1);
+#else
+ invlpg(smp_tlb_invpcid.addr);
+#endif
+ atomic_add_int(&smp_tlb_wait, 1);
+ return (FILTER_HANDLED);
+}
+
+#ifdef __amd64__
+static int
+xen_invlpg_pcid(void *arg)
+{
+#if defined(COUNT_XINVLTLB_HITS) || defined(COUNT_IPIS)
+ int cpu;
+
+ cpu = PCPU_GET(cpuid);
+#ifdef COUNT_XINVLTLB_HITS
+ xhits_pg[cpu]++;
+#endif /* COUNT_XINVLTLB_HITS */
+#ifdef COUNT_IPIS
+ (*ipi_invlpg_counts[cpu])++;
+#endif /* COUNT_IPIS */
+#endif /* COUNT_XINVLTLB_HITS || COUNT_IPIS */
+
+ if (invpcid_works) {
+ invpcid(&smp_tlb_invpcid, INVPCID_ADDR);
+ } else if (smp_tlb_invpcid.pcid == 0) {
+ invlpg(smp_tlb_invpcid.addr);
+ } else if (smp_tlb_invpcid.pcid == (uint64_t)-1) {
+ invltlb_globpcid();
+ } else {
+ uint64_t cr3;
+
+ /*
+ * PCID supported, but INVPCID is not.
+ * Temporarily switch to the target address
+ * space and do INVLPG.
+ */
+ cr3 = rcr3();
+ if (cr3 != pcid_cr3)
+ load_cr3(pcid_cr3 | CR3_PCID_SAVE);
+ invlpg(smp_tlb_invpcid.addr);
+ load_cr3(cr3 | CR3_PCID_SAVE);
+ }
+
+ atomic_add_int(&smp_tlb_wait, 1);
+ return (FILTER_HANDLED);
+}
+#endif
+
+static inline void
+invlpg_range(vm_offset_t start, vm_offset_t end)
+{
+ do {
+ invlpg(start);
+ start += PAGE_SIZE;
+ } while (start < end);
+}
+
+static int
+xen_invlrng(void *arg)
+{
+ vm_offset_t addr;
+#if defined(COUNT_XINVLTLB_HITS) || defined(COUNT_IPIS)
+ int cpu;
+
+ cpu = PCPU_GET(cpuid);
+#ifdef COUNT_XINVLTLB_HITS
+ xhits_rng[cpu]++;
+#endif /* COUNT_XINVLTLB_HITS */
+#ifdef COUNT_IPIS
+ (*ipi_invlrng_counts[cpu])++;
+#endif /* COUNT_IPIS */
+#endif /* COUNT_XINVLTLB_HITS || COUNT_IPIS */
+
+#ifdef __i386__
+ addr = smp_tlb_addr1;
+ invlpg_range(addr, smp_tlb_addr2);
+#else
+ addr = smp_tlb_invpcid.addr;
+ if (pmap_pcid_enabled) {
+ if (invpcid_works) {
+ struct invpcid_descr d;
+
+ d = smp_tlb_invpcid;
+ do {
+ invpcid(&d, INVPCID_ADDR);
+ d.addr += PAGE_SIZE;
+ } while (d.addr < smp_tlb_addr2);
+ } else if (smp_tlb_invpcid.pcid == 0) {
+ /*
+ * kernel pmap - use invlpg to invalidate
+ * global mapping.
+ */
+ invlpg_range(addr, smp_tlb_addr2);
+ } else if (smp_tlb_invpcid.pcid != (uint64_t)-1) {
+ invltlb_globpcid();
+ if (smp_tlb_pmap != NULL) {
+ CPU_CLR_ATOMIC(PCPU_GET(cpuid),
+ &smp_tlb_pmap->pm_save);
+ }
+ } else {
+ uint64_t cr3;
+
+ cr3 = rcr3();
+ if (cr3 != pcid_cr3)
+ load_cr3(pcid_cr3 | CR3_PCID_SAVE);
+ invlpg_range(addr, smp_tlb_addr2);
+ load_cr3(cr3 | CR3_PCID_SAVE);
+ }
+ } else {
+ invlpg_range(addr, smp_tlb_addr2);
+ }
+#endif
+
+ atomic_add_int(&smp_tlb_wait, 1);
+ return (FILTER_HANDLED);
+}
+
+static int
+xen_invlcache(void *arg)
+{
+#ifdef COUNT_IPIS
+ int cpu = PCPU_GET(cpuid);
+
+ cpu = PCPU_GET(cpuid);
+ (*ipi_invlcache_counts[cpu])++;
+#endif /* COUNT_IPIS */
+
+ wbinvd();
+ atomic_add_int(&smp_tlb_wait, 1);
+ return (FILTER_HANDLED);
+}
+
+#ifdef __i386__
+static int
+xen_lazypmap(void *arg)
+{
+
+ pmap_lazyfix_action();
+ return (FILTER_HANDLED);
+}
+#endif
+
+static int
+xen_cpustop_handler(void *arg)
+{
+
+ cpustop_handler();
+ return (FILTER_HANDLED);
+}
+
+static int
+xen_cpususpend_handler(void *arg)
+{
+
+ cpususpend_handler();
+ return (FILTER_HANDLED);
+}
+
+static int
+xen_cpustophard_handler(void *arg)
+{
+
+ ipi_nmi_handler();
+ return (FILTER_HANDLED);
+}
+
+/* Xen PV IPI sender */
+static void
+xen_ipi_vectored(u_int vector, int dest)
+{
+ xen_intr_handle_t *ipi_handle;
+ int ipi_idx, to_cpu, self;
+
+ ipi_idx = IPI_TO_IDX(vector);
+ if (ipi_idx > nitems(xen_ipis))
+ panic("IPI out of range");
+
+ switch(dest) {
+ case APIC_IPI_DEST_SELF:
+ ipi_handle = DPCPU_GET(ipi_handle);
+ xen_intr_signal(ipi_handle[ipi_idx]);
+ break;
+ case APIC_IPI_DEST_ALL:
+ CPU_FOREACH(to_cpu) {
+ ipi_handle = DPCPU_ID_GET(to_cpu, ipi_handle);
+ xen_intr_signal(ipi_handle[ipi_idx]);
+ }
+ break;
+ case APIC_IPI_DEST_OTHERS:
+ self = PCPU_GET(cpuid);
+ CPU_FOREACH(to_cpu) {
+ if (to_cpu != self) {
+ ipi_handle = DPCPU_ID_GET(to_cpu, ipi_handle);
+ xen_intr_signal(ipi_handle[ipi_idx]);
+ }
+ }
+ break;
+ default:
+ to_cpu = apic_cpuid(dest);
+ ipi_handle = DPCPU_ID_GET(to_cpu, ipi_handle);
+ xen_intr_signal(ipi_handle[ipi_idx]);
+ break;
+ }
+}
+
+static void
+xen_cpu_ipi_init(int cpu)
+{
+ xen_intr_handle_t *ipi_handle;
+ const struct xen_ipi_handler *ipi;
+ device_t dev;
+ int idx, rc;
+
+ ipi_handle = DPCPU_ID_GET(cpu, ipi_handle);
+ dev = pcpu_find(cpu)->pc_device;
+ KASSERT((dev != NULL), ("NULL pcpu device_t"));
+
+ for (ipi = xen_ipis, idx = 0; idx < nitems(xen_ipis); ipi++, idx++) {
+
+ if (ipi->filter == NULL) {
+ ipi_handle[idx] = NULL;
+ continue;
+ }
+
+ rc = xen_intr_alloc_and_bind_ipi(dev, cpu, ipi->filter,
+ INTR_TYPE_TTY, &ipi_handle[idx]);
+ if (rc != 0)
+ panic("Unable to allocate a XEN IPI port");
+ xen_intr_describe(ipi_handle[idx], "%s", ipi->description);
+ }
+}
+
+static void
+xen_init_ipis(void)
+{
+ int i;
+
+ if (!xen_hvm_domain() || !xen_vector_callback_enabled)
+ return;
+
+#ifdef __amd64__
+ if (pmap_pcid_enabled) {
+ xen_ipis[IPI_TO_IDX(IPI_INVLTLB)].filter = xen_invltlb_pcid;
+ xen_ipis[IPI_TO_IDX(IPI_INVLPG)].filter = xen_invlpg_pcid;
+ }
+#endif
+ CPU_FOREACH(i)
+ xen_cpu_ipi_init(i);
+
+ /* Set the xen pv ipi ops to replace the native ones */
+ cpu_ops.ipi_vectored = xen_ipi_vectored;
+}
+
+/*---------------------- XEN Hypervisor Probe and Setup ----------------------*/
static uint32_t
xen_hvm_cpuid_base(void)
{
@@ -253,4 +683,5 @@ void xen_hvm_init_cpu(void)
}
SYSINIT(xen_hvm_init, SI_SUB_HYPERVISOR, SI_ORDER_FIRST, xen_hvm_init, NULL);
+SYSINIT(xen_init_ipis, SI_SUB_SMP, SI_ORDER_FIRST, xen_init_ipis, NULL);
SYSINIT(xen_hvm_init_cpu, SI_SUB_INTR, SI_ORDER_FIRST, xen_hvm_init_cpu, NULL);
diff --git a/sys/x86/xen/xen_intr.c b/sys/x86/xen/xen_intr.c
index 83bf487..54a6be6 100644
--- a/sys/x86/xen/xen_intr.c
+++ b/sys/x86/xen/xen_intr.c
@@ -1010,7 +1010,7 @@ xen_intr_bind_virq(device_t dev, u_int virq, u_int cpu,
}
int
-xen_intr_bind_ipi(device_t dev, u_int ipi, u_int cpu,
+xen_intr_alloc_and_bind_ipi(device_t dev, u_int cpu,
driver_filter_t filter, enum intr_type flags,
xen_intr_handle_t *port_handlep)
{
diff --git a/sys/xen/xen_intr.h b/sys/xen/xen_intr.h
index 109608f..3b339a5 100644
--- a/sys/xen/xen_intr.h
+++ b/sys/xen/xen_intr.h
@@ -141,21 +141,20 @@ int xen_intr_bind_virq(device_t dev, u_int virq, u_int cpu,
void *arg, enum intr_type irqflags, xen_intr_handle_t *handlep);
/**
- * Associate an interprocessor interrupt vector with an interrupt handler.
+ * Allocate a local event channel port for servicing interprocessor
+ * interupts and, if successful, associate the port with the specified
+ * interrupt handler.
*
* \param dev The device making this bind request.
- * \param ipi The interprocessor interrupt vector number of the
- * interrupt source being hooked.
* \param cpu The cpu receiving the IPI.
- * \param filter An interrupt filter handler. Specify NULL
- * to always dispatch to the ithread handler.
+ * \param filter The interrupt filter servicing this IPI.
* \param irqflags Interrupt handler flags. See sys/bus.h.
* \param handlep Pointer to an opaque handle used to manage this
* registration.
*
* \returns 0 on success, otherwise an errno.
*/
-int xen_intr_bind_ipi(device_t dev, u_int ipi, u_int cpu,
+int xen_intr_alloc_and_bind_ipi(device_t dev, u_int cpu,
driver_filter_t filter, enum intr_type irqflags,
xen_intr_handle_t *handlep);
OpenPOWER on IntegriCloud