diff options
Diffstat (limited to 'sys/i386')
-rw-r--r-- | sys/i386/i386/mp_machdep.c | 10 | ||||
-rw-r--r-- | sys/i386/include/cpu.h | 11 | ||||
-rw-r--r-- | sys/i386/include/pcpu.h | 9 | ||||
-rw-r--r-- | sys/i386/include/smp.h | 5 | ||||
-rw-r--r-- | sys/i386/xen/mp_machdep.c | 113 |
5 files changed, 84 insertions, 64 deletions
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])); } /* |