diff --git a/sys/dev/xen/bus/intr-internal.h b/sys/dev/xen/bus/intr-internal.h --- a/sys/dev/xen/bus/intr-internal.h +++ b/sys/dev/xen/bus/intr-internal.h @@ -77,6 +77,9 @@ * . The architecture may implement these as inline. */ void xen_arch_intr_init(void); +struct xenisrc *xen_arch_intr_alloc(void); +void xen_arch_intr_release(struct xenisrc *isrc); +u_int xen_arch_intr_next_cpu(struct xenisrc *isrc); u_long xen_arch_intr_execute_handlers(struct xenisrc *isrc, struct trapframe *frame); int xen_arch_intr_add_handler(const char *name, diff --git a/sys/x86/include/xen/arch-intr.h b/sys/x86/include/xen/arch-intr.h --- a/sys/x86/include/xen/arch-intr.h +++ b/sys/x86/include/xen/arch-intr.h @@ -30,20 +30,29 @@ #define _MACHINE__XEN_ARCH_INTR_H_ #include +#include typedef struct { struct intsrc intsrc; /* @TOP -> *xen_arch_isrc */ u_int vector; /* Global isrc vector number */ } xen_arch_isrc_t; -extern struct pic xen_intr_pic; - #include /******************************* ARCH wrappers *******************************/ extern void xen_arch_intr_init(void); +extern struct xenisrc *xen_arch_intr_alloc(void); +extern void xen_arch_intr_release(struct xenisrc *isrc); + +static inline u_int +xen_arch_intr_next_cpu(struct xenisrc *isrc) +{ + + return (apic_cpuid(intr_next_cpu(0))); +} + static inline u_long xen_arch_intr_execute_handlers(struct xenisrc *isrc, struct trapframe *frame) { diff --git a/sys/x86/xen/xen_arch_intr.c b/sys/x86/xen/xen_arch_intr.c --- a/sys/x86/xen/xen_arch_intr.c +++ b/sys/x86/xen/xen_arch_intr.c @@ -111,6 +111,41 @@ /******************************** EVTCHN PIC *********************************/ +static MALLOC_DEFINE(M_XENINTR, "xen_intr", "Xen Interrupt Services"); + +/* + * Lock for x86-related structures. Notably modifying + * xen_intr_auto_vector_count, and allocating interrupts require this lock be + * held. + */ +static struct mtx xen_intr_x86_lock; + +static u_int first_evtchn_irq; + +static u_int xen_intr_auto_vector_count; + +/* + * list of released isrcs + * This is meant to overlay struct xenisrc, with only the xen_arch_isrc_t + * portion being preserved, everything else can be wiped. + */ +struct avail_list { + xen_arch_isrc_t preserve; + SLIST_ENTRY(avail_list) free; +}; +static SLIST_HEAD(free, avail_list) avail_list = + SLIST_HEAD_INITIALIZER(avail_list); + +void +xen_intr_alloc_irqs(void) +{ + + if (num_io_irqs > UINT_MAX - NR_EVENT_CHANNELS) + panic("IRQ allocation overflow (num_msi_irqs too high?)"); + first_evtchn_irq = num_io_irqs; + num_io_irqs += NR_EVENT_CHANNELS; +} + static void xen_intr_pic_enable_source(struct intsrc *isrc) { @@ -244,7 +279,7 @@ /** * PIC interface for all event channel port types except physical IRQs. */ -struct pic xen_intr_pic = { +static 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, @@ -265,8 +300,86 @@ { int error; + mtx_init(&xen_intr_x86_lock, "xen-x86-table-lock", NULL, MTX_DEF); + error = intr_register_pic(&xen_intr_pic); if (error != 0) panic("%s(): failed registering Xen/x86 PIC, error=%d\n", __func__, error); } + +/** + * Allocate a Xen interrupt source object. + * + * \param type The type of interrupt source to create. + * + * \return A pointer to a newly allocated Xen interrupt source + * object or NULL. + */ +struct xenisrc * +xen_arch_intr_alloc(void) +{ + static int warned; + struct xenisrc *isrc; + unsigned int vector; + int error; + + mtx_lock(&xen_intr_x86_lock); + isrc = (struct xenisrc *)SLIST_FIRST(&avail_list); + if (isrc != NULL) { + SLIST_REMOVE_HEAD(&avail_list, free); + mtx_unlock(&xen_intr_x86_lock); + + KASSERT(isrc->xi_arch.intsrc.is_pic == &xen_intr_pic, + ("interrupt not owned by Xen code?")); + + KASSERT(isrc->xi_arch.intsrc.is_handlers == 0, + ("Free evtchn still has handlers")); + + return (isrc); + } + + if (xen_intr_auto_vector_count >= NR_EVENT_CHANNELS) { + if (!warned) { + warned = 1; + printf("%s: Xen interrupts exhausted.\n", __func__); + } + mtx_unlock(&xen_intr_x86_lock); + return (NULL); + } + + vector = first_evtchn_irq + xen_intr_auto_vector_count; + xen_intr_auto_vector_count++; + + KASSERT((intr_lookup_source(vector) == NULL), + ("Trying to use an already allocated vector")); + + mtx_unlock(&xen_intr_x86_lock); + isrc = malloc(sizeof(*isrc), M_XENINTR, M_WAITOK | M_ZERO); + isrc->xi_arch.intsrc.is_pic = &xen_intr_pic; + isrc->xi_arch.vector = vector; + error = intr_register_source(&isrc->xi_arch.intsrc); + if (error != 0) + panic("%s(): failed registering interrupt %u, error=%d\n", + __func__, vector, error); + + return (isrc); +} + +void +xen_arch_intr_release(struct xenisrc *isrc) +{ + + KASSERT(isrc->xi_arch.intsrc.is_handlers == 0, + ("Release called, but xenisrc still in use")); + + _Static_assert(sizeof(struct xenisrc) >= sizeof(struct avail_list), + "unused structure MUST be no larger than in-use structure"); + _Static_assert(offsetof(struct xenisrc, xi_arch) == + offsetof(struct avail_list, preserve), + "unused structure does not properly overlay in-use structure"); + + mtx_lock(&xen_intr_x86_lock); + SLIST_INSERT_HEAD(&avail_list, (struct avail_list *)isrc, free); + mtx_unlock(&xen_intr_x86_lock); +} diff --git a/sys/x86/xen/xen_intr.c b/sys/x86/xen/xen_intr.c --- a/sys/x86/xen/xen_intr.c +++ b/sys/x86/xen/xen_intr.c @@ -38,7 +38,6 @@ #include #include #include -#include #include #include #include @@ -68,17 +67,6 @@ #include #endif -static MALLOC_DEFINE(M_XENINTR, "xen_intr", "Xen Interrupt Services"); - -/* - * Lock for x86-related structures. Notably modifying - * xen_intr_auto_vector_count, and allocating interrupts require this lock be - * held. - */ -static struct mtx xen_intr_x86_lock; - -static u_int first_evtchn_irq; - /** * Per-cpu event channel processing state. */ @@ -128,21 +116,8 @@ * Acquire/release operations for isrc->xi_refcount require this lock be held. */ static struct mtx xen_intr_isrc_lock; -static u_int xen_intr_auto_vector_count; static struct xenisrc *xen_intr_port_to_isrc[NR_EVENT_CHANNELS]; -/* - * list of released isrcs - * This is meant to overlay struct xenisrc, with only the xen_arch_isrc_t - * portion being preserved, everything else can be wiped. - */ -struct avail_list { - xen_arch_isrc_t preserve; - SLIST_ENTRY(avail_list) free; -}; -static SLIST_HEAD(free, avail_list) avail_list = - SLIST_HEAD_INITIALIZER(avail_list); - /*------------------------- Private Functions --------------------------------*/ /** @@ -220,64 +195,6 @@ xen_set_bit(port, pcpu->evtchn_enabled); } -/** - * Allocate a Xen interrupt source object. - * - * \param type The type of interrupt source to create. - * - * \return A pointer to a newly allocated Xen interrupt source - * object or NULL. - */ -static struct xenisrc * -xen_intr_alloc_isrc(void) -{ - static int warned; - struct xenisrc *isrc; - unsigned int vector; - int error; - - mtx_lock(&xen_intr_x86_lock); - isrc = (struct xenisrc *)SLIST_FIRST(&avail_list); - if (isrc != NULL) { - SLIST_REMOVE_HEAD(&avail_list, free); - mtx_unlock(&xen_intr_x86_lock); - - KASSERT(isrc->xi_arch.intsrc.is_pic == &xen_intr_pic, - ("interrupt not owned by Xen code?")); - - KASSERT(isrc->xi_arch.intsrc.is_handlers == 0, - ("Free evtchn still has handlers")); - - return (isrc); - } - - if (xen_intr_auto_vector_count >= NR_EVENT_CHANNELS) { - if (!warned) { - warned = 1; - printf("%s: Xen interrupts exhausted.\n", __func__); - } - mtx_unlock(&xen_intr_x86_lock); - return (NULL); - } - - vector = first_evtchn_irq + xen_intr_auto_vector_count; - xen_intr_auto_vector_count++; - - KASSERT((intr_lookup_source(vector) == NULL), - ("Trying to use an already allocated vector")); - - mtx_unlock(&xen_intr_x86_lock); - isrc = malloc(sizeof(*isrc), M_XENINTR, M_WAITOK | M_ZERO); - isrc->xi_arch.intsrc.is_pic = &xen_intr_pic; - isrc->xi_arch.vector = vector; - error = intr_register_source(&isrc->xi_arch.intsrc); - if (error != 0) - panic("%s(): failed registering interrupt %u, error=%d\n", - __func__, vector, error); - - return (isrc); -} - /** * Attempt to free an active Xen interrupt source object. * @@ -289,8 +206,6 @@ xen_intr_release_isrc(struct xenisrc *isrc) { - KASSERT(isrc->xi_arch.intsrc.is_handlers == 0, - ("Release called, but xenisrc still in use")); mtx_lock(&xen_intr_isrc_lock); if (is_valid_evtchn(isrc->xi_port)) { evtchn_mask_port(isrc->xi_port); @@ -312,15 +227,7 @@ /* not reachable from xen_intr_port_to_isrc[], unlock */ mtx_unlock(&xen_intr_isrc_lock); - _Static_assert(sizeof(struct xenisrc) >= sizeof(struct avail_list), - "unused structure MUST be no larger than in-use structure"); - _Static_assert(offsetof(struct xenisrc, xi_arch) == - offsetof(struct avail_list, preserve), - "unused structure does not properly overlay in-use structure"); - - mtx_lock(&xen_intr_x86_lock); - SLIST_INSERT_HEAD(&avail_list, (struct avail_list *)isrc, free); - mtx_unlock(&xen_intr_x86_lock); + xen_arch_intr_release(isrc); return (0); } @@ -361,7 +268,7 @@ } *port_handlep = NULL; - isrc = xen_intr_alloc_isrc(); + isrc = xen_arch_intr_alloc(); if (isrc == NULL) return (ENOSPC); @@ -382,7 +289,7 @@ * unless specified otherwise, so shuffle them to balance * the interrupt load. */ - xen_intr_assign_cpu(isrc, apic_cpuid(intr_next_cpu(0))); + xen_intr_assign_cpu(isrc, xen_arch_intr_next_cpu(isrc)); } #endif @@ -561,8 +468,6 @@ mtx_init(&xen_intr_isrc_lock, "xen-irq-lock", NULL, MTX_DEF); - mtx_init(&xen_intr_x86_lock, "xen-x86-table-lock", NULL, MTX_DEF); - /* * Set the per-cpu mask of CPU#0 to enable all, since by default all * event channels are bound to CPU#0. @@ -585,16 +490,6 @@ } SYSINIT(xen_intr_init, SI_SUB_INTR, SI_ORDER_SECOND, xen_intr_init, NULL); -void -xen_intr_alloc_irqs(void) -{ - - if (num_io_irqs > UINT_MAX - NR_EVENT_CHANNELS) - panic("IRQ allocation overflow (num_msi_irqs too high?)"); - first_evtchn_irq = num_io_irqs; - num_io_irqs += NR_EVENT_CHANNELS; -} - /*--------------------------- Common PIC Functions ---------------------------*/ static void