Index: sys/conf/files.x86 =================================================================== --- sys/conf/files.x86 +++ sys/conf/files.x86 @@ -334,3 +334,4 @@ x86/x86/delay.c standard x86/xen/hvm.c optional xenhvm x86/xen/xen_apic.c optional xenhvm +x86/xen/xen_arch_intr.c optional xenhvm Index: sys/x86/include/xen/arch-intr.h =================================================================== --- sys/x86/include/xen/arch-intr.h +++ sys/x86/include/xen/arch-intr.h @@ -40,4 +40,56 @@ typedef struct xen_arch_isrc xen_arch_isrc_t; +extern struct pic xen_intr_pic; + +#include + +/****************************** ARCH wrappers ********************************/ + +static inline bool +xen_arch_intr_has_handlers(struct xenisrc *isrc) +{ + + return (isrc->xi_arch.xai_intsrc.is_handlers != 0); +} + +static inline bool +xen_arch_intr_execute_handlers(struct xenisrc *isrc, struct trapframe *frame) +{ + + intr_execute_handlers(&isrc->xi_arch.xai_intsrc, frame); + return (true); +} + +static inline int +xen_arch_intr_add_handler(const char *name, driver_filter_t filter, + driver_intr_t handler, void *arg, enum intr_type flags, + struct xenisrc *isrc, void **cookiep) +{ + + return (intr_add_handler(name, isrc->xi_arch.xai_vector, filter, + handler, arg, flags, cookiep, 0)); +} + +static inline int +xen_arch_intr_describe(struct xenisrc *isrc, void *cookie, const char *descr) +{ + + return (intr_describe(isrc->xi_arch.xai_vector, cookie, descr)); +} + +static inline int +xen_arch_intr_remove_handler(struct xenisrc *isrc, void *cookie) +{ + + return (intr_remove_handler(cookie)); +} + +static inline int +xen_arch_intr_event_bind(struct xenisrc *isrc, u_int cpu) +{ + + return (intr_event_bind(isrc->xi_arch.xai_intsrc.is_event, cpu)); +} + #endif /* _MACHINE_X86_XEN_ARCH_INTR_H_ */ Index: sys/x86/xen/xen_arch_intr.c =================================================================== --- /dev/null +++ sys/x86/xen/xen_arch_intr.c @@ -0,0 +1,199 @@ +/* + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2015 Julien Grall + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +/********************************* EVTCHN PIC ********************************/ + +static void +xen_intr_pic_enable_source(struct intsrc *isrc) +{ + + CTASSERT(offsetof(struct xenisrc, xi_arch.xai_intsrc) == 0); + + xen_intr_enable_source((struct xenisrc *)isrc); +} + +static void +xen_intr_pic_disable_source(struct intsrc *isrc, int eoi) +{ + + CTASSERT(offsetof(struct xenisrc, xi_arch.xai_intsrc) == 0); + + xen_intr_disable_source((struct xenisrc *)isrc, eoi == PIC_EOI); +} + +static void +xen_intr_pic_eoi_source(struct intsrc *isrc) +{ + + CTASSERT(offsetof(struct xenisrc, xi_arch.xai_intsrc) == 0); + + xen_intr_eoi_source((struct xenisrc *)isrc); +} + +static void +xen_intr_pic_enable_intr(struct intsrc *isrc) +{ + + CTASSERT(offsetof(struct xenisrc, xi_arch.xai_intsrc) == 0); + + xen_intr_enable_intr((struct xenisrc *)isrc); +} + +static void +xen_intr_pic_disable_intr(struct intsrc *isrc) +{ + + CTASSERT(offsetof(struct xenisrc, xi_arch.xai_intsrc) == 0); + + xen_intr_disable_intr((struct xenisrc *)isrc); +} + +/** + * Determine the global interrupt vector number for + * a Xen interrupt source. + * + * \param isrc The interrupt source to query. + * + * \return The vector number corresponding to the given interrupt source. + */ +static int +xen_intr_pic_vector(struct intsrc *isrc) +{ + + CTASSERT(offsetof(struct xenisrc, xi_arch.xai_intsrc) == 0); + + return (((xen_arch_isrc_t *)isrc)->xai_vector); +} + +/** + * Determine whether or not interrupt events are pending on the + * the given interrupt source. + * + * \param isrc The interrupt source to query. + * + * \returns 0 if no events are pending, otherwise non-zero. + */ +static int +xen_intr_pic_source_pending(struct intsrc *isrc) +{ + /* + * EventChannels are edge triggered and never masked. + * There can be no pending events. + */ + return (0); +} + +static void +xen_intr_pic_suspend(struct pic *pic) +{ + + xen_intr_suspend(); +} + +static void +xen_intr_pic_resume(struct pic *pic, bool suspend_cancelled) +{ + + xen_intr_resume(suspend_cancelled); +} + +/** + * Perform configuration of an interrupt source. + * + * \param isrc The interrupt source to configure. + * \param trig Edge or level. + * \param pol Active high or low. + * + * \returns 0 if no events are pending, otherwise non-zero. + */ +static int +xen_intr_pic_config_intr(struct intsrc *isrc, enum intr_trigger trig, + enum intr_polarity pol) +{ + /* Configuration is only possible via the evtchn apis. */ + return (ENODEV); +} + + +static int +xen_intr_pic_assign_cpu(struct intsrc *isrc, u_int apic_id) +{ + + CTASSERT(offsetof(struct xenisrc, xi_arch.xai_intsrc) == 0); + + return (xen_intr_assign_cpu((struct xenisrc *)isrc, + apic_cpuid(apic_id))); +} + +/** + * PIC interface for all event channel port types except physical IRQs. + */ +struct pic xen_intr_pic = { + .pic_enable_source = xen_intr_pic_enable_source, + .pic_disable_source = xen_intr_pic_disable_source, + .pic_eoi_source = xen_intr_pic_eoi_source, + .pic_enable_intr = xen_intr_pic_enable_intr, + .pic_disable_intr = xen_intr_pic_disable_intr, + .pic_vector = xen_intr_pic_vector, + .pic_source_pending = xen_intr_pic_source_pending, + .pic_suspend = xen_intr_pic_suspend, + .pic_resume = xen_intr_pic_resume, + .pic_config_intr = xen_intr_pic_config_intr, + .pic_assign_cpu = xen_intr_pic_assign_cpu +}; + +/****************************** ARCH wrappers ********************************/ + +void +xen_arch_intr_init(void) +{ + + intr_register_pic(&xen_intr_pic); +} Index: sys/xen/arch-intr.h =================================================================== --- /dev/null +++ sys/xen/arch-intr.h @@ -0,0 +1,86 @@ +/* + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2015 Julien Grall + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _XEN_ARCH_INTR_H_ +#define _XEN_ARCH_INTR_H_ + +enum evtchn_type { + EVTCHN_TYPE_UNBOUND, + EVTCHN_TYPE_VIRQ, + EVTCHN_TYPE_IPI, + EVTCHN_TYPE_PORT, + EVTCHN_TYPE_COUNT +}; + +struct xenisrc { + xen_arch_isrc_t xi_arch; /* @TOP -> *xi_arch=*xenisrc */ + enum evtchn_type xi_type; + u_int xi_cpu; /* VCPU for delivery */ + evtchn_port_t xi_port; + u_int xi_virq; + void *xi_cookie; + u_int xi_close:1; /* close on unbind? */ + u_int xi_masked:1; + volatile u_int xi_refcount; +}; + +/***************** Functions called by the architecture code *****************/ + +void xen_intr_suspend(void); +void xen_intr_resume(bool suspend_cancelled); +void xen_intr_enable_source(struct xenisrc *isrc); +void xen_intr_disable_source(struct xenisrc *isrc, bool need_eoi); +void xen_intr_eoi_source(struct xenisrc *isrc); +void xen_intr_enable_intr(struct xenisrc *isrc); +void xen_intr_disable_intr(struct xenisrc *isrc); +int xen_intr_assign_cpu(struct xenisrc *isrc, u_int to_cpu); + +/******************* Functions implemented by each architecture **************/ + +void xen_arch_intr_init(void); + +#if 0 +/* + * These are sample prototypes, the architecture should include its own in + * . This allows the architecture to implement + * these as inline. + */ +bool xen_arch_intr_has_handlers(struct xenisrc *isrc); +bool xen_arch_intr_execute_handlers(struct xenisrc *isrc, + struct trapframe *frame); +int xen_arch_intr_add_handler(const char *name, driver_filter_t filter, + driver_intr_t handler, void *arg, enum intr_type flags, + struct xenisrc *isrc, void **cookiep); +int xen_arch_intr_describe(struct xenisrc *isrc, void *cookie, + const char *descr); +int xen_arch_intr_remove_handler(struct xenisrc *isrc, void *cookie); +int xen_arch_intr_event_bind(struct xenisrc *isrc, u_int cpu); +#endif + +#endif /* _XEN_ARCH_INTR_H_ */ Index: sys/xen/evtchn/evtchnvar.h =================================================================== --- sys/xen/evtchn/evtchnvar.h +++ sys/xen/evtchn/evtchnvar.h @@ -37,14 +37,6 @@ #include #include -enum evtchn_type { - EVTCHN_TYPE_UNBOUND, - EVTCHN_TYPE_VIRQ, - EVTCHN_TYPE_IPI, - EVTCHN_TYPE_PORT, - EVTCHN_TYPE_COUNT -}; - /** Submit a port notification for delivery to a userland evtchn consumer */ void evtchn_device_upcall(evtchn_port_t port); Index: sys/xen/xen_intr.c =================================================================== --- sys/xen/xen_intr.c +++ sys/xen/xen_intr.c @@ -50,9 +50,6 @@ #include #include -#include -#include -#include #include #include @@ -121,48 +118,6 @@ DPCPU_DECLARE(struct vcpu_info *, vcpu_info); -struct xenisrc { - xen_arch_isrc_t xi_arch; /* @TOP -> *xi_arch=*xenisrc */ - enum evtchn_type xi_type; - u_int xi_cpu; /* VCPU for delivery. */ - evtchn_port_t xi_port; - u_int xi_virq; - void *xi_cookie; - u_int xi_close:1; /* close on unbind? */ - u_int xi_masked:1; - volatile u_int xi_refcount; -}; - -static void xen_intr_suspend(struct pic *); -static void xen_intr_resume(struct pic *, bool suspend_cancelled); -static void xen_intr_enable_source(struct intsrc *isrc); -static void xen_intr_disable_source(struct intsrc *isrc, int eoi); -static void xen_intr_eoi_source(struct intsrc *isrc); -static void xen_intr_enable_intr(struct intsrc *isrc); -static void xen_intr_disable_intr(struct intsrc *isrc); -static int xen_intr_vector(struct intsrc *isrc); -static int xen_intr_source_pending(struct intsrc *isrc); -static int xen_intr_config_intr(struct intsrc *isrc, - enum intr_trigger trig, enum intr_polarity pol); -static int xen_intr_assign_cpu(struct intsrc *isrc, u_int to_cpu); - -/** - * PIC interface for all event channel port types except physical IRQs. - */ -struct pic xen_intr_pic = { - .pic_enable_source = xen_intr_enable_source, - .pic_disable_source = xen_intr_disable_source, - .pic_eoi_source = xen_intr_eoi_source, - .pic_enable_intr = xen_intr_enable_intr, - .pic_disable_intr = xen_intr_disable_intr, - .pic_vector = xen_intr_vector, - .pic_source_pending = xen_intr_source_pending, - .pic_suspend = xen_intr_suspend, - .pic_resume = xen_intr_resume, - .pic_config_intr = xen_intr_config_intr, - .pic_assign_cpu = xen_intr_assign_cpu -}; - /* * Lock for interrupt core data. * @@ -297,7 +252,7 @@ isrc = (struct xenisrc *)intr_lookup_source(vector); if (isrc != NULL && isrc->xi_type == EVTCHN_TYPE_UNBOUND) { - KASSERT(isrc->xi_arch.xai_intsrc.is_handlers == 0, + KASSERT(!xen_arch_intr_has_handlers(isrc), ("Free evtchn still has handlers")); isrc->xi_type = type; return (isrc); @@ -369,7 +324,7 @@ { mtx_lock(&xen_intr_isrc_lock); - KASSERT(isrc->xi_arch.xai_intsrc.is_handlers == 0, + KASSERT(!xen_arch_intr_has_handlers(isrc), ("Release called, but xenisrc still in use")); evtchn_mask_port(isrc->xi_port); evtchn_clear_port(isrc->xi_port); @@ -460,7 +415,7 @@ * unless specified otherwise, so shuffle them to balance * the interrupt load. */ - xen_intr_assign_cpu(&isrc->xi_arch.xai_intsrc, intr_next_cpu(0)); + xen_intr_assign_cpu(isrc, intr_next_cpu(0)); } #endif @@ -597,7 +552,7 @@ ("Received unexpected event on vCPU#%d, event bound to vCPU#%u", PCPU_GET(cpuid), isrc->xi_cpu)); - intr_execute_handlers(&isrc->xi_arch.xai_intsrc, trap_frame); + xen_arch_intr_execute_handlers(isrc, trap_frame); /* * If this is the final port processed, @@ -651,7 +606,7 @@ for (i = 0; i < nitems(s->evtchn_mask); i++) atomic_store_rel_long(&s->evtchn_mask[i], ~0UL); - intr_register_pic(&xen_intr_pic); + xen_arch_intr_init(); if (bootverbose) printf("Xen interrupt system initialized\n"); @@ -691,9 +646,10 @@ /** * Prepare this PIC for system suspension. */ -static void -xen_intr_suspend(struct pic *unused) +void +xen_intr_suspend(void) { + /* Nothing to do on suspend */ } static void @@ -765,7 +721,7 @@ #ifdef SMP isrc->xi_cpu = 0; - error = xen_intr_assign_cpu(&isrc->xi_arch.xai_intsrc, cpu); + error = xen_intr_assign_cpu(isrc, cpu); if (error) panic(errfmt, __func__, cpu, error, isrc->xi_virq); #endif @@ -778,8 +734,8 @@ /** * Return this PIC to service after being suspended. */ -static void -xen_intr_resume(struct pic *unused, bool suspend_cancelled) +void +xen_intr_resume(bool suspend_cancelled) { shared_info_t *s = HYPERVISOR_shared_info; u_int isrc_idx; @@ -831,67 +787,13 @@ * * \param isrc The interrupt source to disable. */ -static void -xen_intr_disable_intr(struct intsrc *base_isrc) +void +xen_intr_disable_intr(struct xenisrc *isrc) { - struct xenisrc *isrc = (struct xenisrc *)base_isrc; - CTASSERT(offsetof(struct xenisrc, xi_arch.xai_intsrc) == 0); evtchn_mask_port(isrc->xi_port); } -/** - * Determine the global interrupt vector number for - * a Xen interrupt source. - * - * \param isrc The interrupt source to query. - * - * \return The vector number corresponding to the given interrupt source. - */ -static int -xen_intr_vector(struct intsrc *base_isrc) -{ - struct xenisrc *isrc = (struct xenisrc *)base_isrc; - CTASSERT(offsetof(struct xenisrc, xi_arch.xai_intsrc) == 0); - - return (isrc->xi_arch.xai_vector); -} - -/** - * Determine whether or not interrupt events are pending on the - * the given interrupt source. - * - * \param isrc The interrupt source to query. - * - * \returns 0 if no events are pending, otherwise non-zero. - */ -static int -xen_intr_source_pending(struct intsrc *isrc) -{ - /* - * EventChannels are edge triggered and never masked. - * There can be no pending events. - */ - return (0); -} - -/** - * Perform configuration of an interrupt source. - * - * \param isrc The interrupt source to configure. - * \param trig Edge or level. - * \param pol Active high or low. - * - * \returns 0 if no events are pending, otherwise non-zero. - */ -static int -xen_intr_config_intr(struct intsrc *isrc, enum intr_trigger trig, - enum intr_polarity pol) -{ - /* Configuration is only possible via the evtchn apis. */ - return (ENODEV); -} - /** * Configure CPU affinity for interrupt source event delivery. * @@ -900,21 +802,18 @@ * * \returns 0 if successful, otherwise an errno. */ -static int -xen_intr_assign_cpu(struct intsrc *base_isrc, u_int to_cpu) +int +xen_intr_assign_cpu(struct xenisrc *isrc, u_int to_cpu) { #ifdef SMP struct evtchn_bind_vcpu bind_vcpu; - struct xenisrc *isrc; u_int vcpu_id = PCPU_ID_GET(to_cpu); int error, masked; - CTASSERT(offsetof(struct xenisrc, xi_arch.xai_intsrc) == 0); if (!xen_has_percpu_evtchn()) return (EOPNOTSUPP); mtx_lock(&xen_intr_isrc_lock); - isrc = (struct xenisrc *)base_isrc; if (isrc->xi_port >= NR_EVENT_CHANNELS) { mtx_unlock(&xen_intr_isrc_lock); return (EINVAL); @@ -965,17 +864,13 @@ /* * Mask a level triggered interrupt source. * - * \param isrc The interrupt source to mask (if necessary). - * \param eoi If non-zero, perform any necessary end-of-interrupt - * acknowledgements. + * \param isrc The interrupt source to mask (if necessary). + * \param need_eoi If true, perform any necessary end-of-interrupt + * acknowledgements. */ -static void -xen_intr_disable_source(struct intsrc *base_isrc, int eoi) +void +xen_intr_disable_source(struct xenisrc *isrc, bool need_eoi) { - struct xenisrc *isrc; - CTASSERT(offsetof(struct xenisrc, xi_arch.xai_intsrc) == 0); - - isrc = (struct xenisrc *)base_isrc; /* * NB: checking if the event channel is already masked is @@ -993,14 +888,9 @@ * * \param isrc The interrupt source to unmask (if necessary). */ -static void -xen_intr_enable_source(struct intsrc *base_isrc) +void +xen_intr_enable_source(struct xenisrc *isrc) { - struct xenisrc *isrc; - CTASSERT(offsetof(struct xenisrc, xi_arch.xai_intsrc) == 0); - - isrc = (struct xenisrc *)base_isrc; - if (isrc->xi_masked == 0) evtchn_unmask_port(isrc->xi_port); } @@ -1010,10 +900,9 @@ * * \param isrc The interrupt source to EOI. */ -static void -xen_intr_eoi_source(struct intsrc *base_isrc) +void +xen_intr_eoi_source(struct xenisrc *isrc) { - CTASSERT(offsetof(struct xenisrc, xi_arch.xai_intsrc) == 0); } /* @@ -1021,11 +910,9 @@ * * \param isrc The interrupt source to enable. */ -static void -xen_intr_enable_intr(struct intsrc *base_isrc) +void +xen_intr_enable_intr(struct xenisrc *isrc) { - struct xenisrc *isrc = (struct xenisrc *)base_isrc; - CTASSERT(offsetof(struct xenisrc, xi_arch.xai_intsrc) == 0); evtchn_unmask_port(isrc->xi_port); } @@ -1154,7 +1041,7 @@ #ifdef SMP if (error == 0) - error = intr_event_bind(isrc->xi_arch.xai_intsrc.is_event, cpu); + error = xen_arch_intr_event_bind(isrc, cpu); #endif if (error != 0) { @@ -1174,7 +1061,7 @@ * masks manually so events can't fire on the wrong cpu * during AP startup. */ - xen_intr_assign_cpu(&isrc->xi_arch.xai_intsrc, cpu); + xen_intr_assign_cpu(isrc, cpu); } #endif @@ -1230,7 +1117,7 @@ * masks manually so events can't fire on the wrong cpu * during AP startup. */ - xen_intr_assign_cpu(&isrc->xi_arch.xai_intsrc, cpu); + xen_intr_assign_cpu(isrc, cpu); } /* @@ -1258,7 +1145,8 @@ va_start(ap, fmt); vsnprintf(descr, sizeof(descr), fmt, ap); va_end(ap); - return (intr_describe(isrc->xi_arch.xai_vector, isrc->xi_cookie, descr)); + + return (xen_arch_intr_describe(isrc, isrc->xi_cookie, descr)); } void @@ -1281,8 +1169,10 @@ } mtx_unlock(&xen_intr_isrc_lock); - if (isrc->xi_cookie != NULL) - intr_remove_handler(isrc->xi_cookie); + if (isrc->xi_cookie != NULL) { + xen_arch_intr_remove_handler(isrc, isrc->xi_cookie); + isrc->xi_cookie = NULL; + } xen_intr_release_isrc(isrc); } @@ -1325,8 +1215,8 @@ if (isrc == NULL || isrc->xi_cookie != NULL) return (EINVAL); - error = intr_add_handler(name, isrc->xi_arch.xai_vector,filter, handler, arg, - flags|INTR_EXCL, &isrc->xi_cookie, 0); + error = xen_arch_intr_add_handler(name, filter, handler, arg, + flags | INTR_EXCL, isrc, &isrc->xi_cookie); if (error != 0) printf("%s: %s: add handler failed: %d\n", name, __func__, error);