git: 2d795ab1eaa7 - main - xen/intr: move x86 PIC interface to xen_arch_intr.c, introduce wrappers
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Fri, 14 Apr 2023 14:01:04 UTC
The branch main has been updated by royger: URL: https://cgit.FreeBSD.org/src/commit/?id=2d795ab1eaa78c6dd5d214285db7f94ff870bd45 commit 2d795ab1eaa78c6dd5d214285db7f94ff870bd45 Author: Julien Grall <julien@xen.org> AuthorDate: 2015-10-20 16:14:56 +0000 Commit: Roger Pau Monné <royger@FreeBSD.org> CommitDate: 2023-04-14 13:58:56 +0000 xen/intr: move x86 PIC interface to xen_arch_intr.c, introduce wrappers The x86 PIC interface is very much x86-specific and not used by other architectures. Since most of xen_intr.c can be shared with other architectures, the PIC interface needs to be broken off. Introduce wrappers for calls into the architecture-dependent interrupt layer. All architectures need roughly the same functionality, but the interface is slightly different between architectures. Due to the wrappers being so thin, all of them are implemented as inline in arch-intr.h. The original implementation was done by Julien Grall in 2015, but this has required major updating. Removal of PVHv1 meant substantial portions disappeared. The original implementation took care of moving interrupt allocation to xen_arch_intr.c, but this has required massive rework and was broken off. In the original implementation the wrappers were normal functions. Some had empty stubs in xen_intr.c and were removed. Reviewed by: royger Submitted by: Elliott Mitchell <ehem+freebsd@m5p.com> Original implementation: Julien Grall <julien@xen.org>, 2015-10-20 09:14:56 Differential Revision: https://reviews.freebsd.org/D30909 --- sys/dev/xen/bus/intr-internal.h | 30 +++++++ sys/x86/include/xen/arch-intr.h | 45 +++++++++++ sys/x86/xen/xen_arch_intr.c | 171 +++++++++++++++++++++++++++++++++++++++- sys/x86/xen/xen_intr.c | 170 ++++++--------------------------------- 4 files changed, 268 insertions(+), 148 deletions(-) diff --git a/sys/dev/xen/bus/intr-internal.h b/sys/dev/xen/bus/intr-internal.h index 18f148bcb45f..2c707edf095e 100644 --- a/sys/dev/xen/bus/intr-internal.h +++ b/sys/dev/xen/bus/intr-internal.h @@ -60,4 +60,34 @@ struct xenisrc { volatile u_int xi_refcount; }; +/***************** Functions called by the architecture code *****************/ + +extern void xen_intr_resume(void); +extern void xen_intr_enable_source(struct xenisrc *isrc); +extern void xen_intr_disable_source(struct xenisrc *isrc); +extern void xen_intr_enable_intr(struct xenisrc *isrc); +extern void xen_intr_disable_intr(struct xenisrc *isrc); +extern int xen_intr_assign_cpu(struct xenisrc *isrc, u_int to_cpu); + +/******************* Functions implemented by each architecture **************/ + +#if 0 +/* + * These are sample prototypes, the architecture should include its own in + * <machine/xen/arch-intr.h>. The architecture may implement these as inline. + */ +void xen_arch_intr_init(void); +u_long 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_INTR_INTERNAL_H_ */ diff --git a/sys/x86/include/xen/arch-intr.h b/sys/x86/include/xen/arch-intr.h index b721e744852a..06e70ba462a2 100644 --- a/sys/x86/include/xen/arch-intr.h +++ b/sys/x86/include/xen/arch-intr.h @@ -36,6 +36,51 @@ typedef struct { u_int vector; /* Global isrc vector number */ } xen_arch_isrc_t; +extern struct pic xen_intr_pic; + #include <dev/xen/bus/intr-internal.h> +/******************************* ARCH wrappers *******************************/ + +extern void xen_arch_intr_init(void); + +static inline u_long +xen_arch_intr_execute_handlers(struct xenisrc *isrc, struct trapframe *frame) +{ + + intr_execute_handlers(&isrc->xi_arch.intsrc, frame); + return (0); +} + +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.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.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.intsrc.is_event, cpu)); +} + #endif /* _MACHINE__XEN_ARCH_INTR_H_ */ diff --git a/sys/x86/xen/xen_arch_intr.c b/sys/x86/xen/xen_arch_intr.c index d946ca781355..94ada3dee4e9 100644 --- a/sys/x86/xen/xen_arch_intr.c +++ b/sys/x86/xen/xen_arch_intr.c @@ -1,6 +1,7 @@ /*- * SPDX-License-Identifier: MIT OR GPL-2.0-only * + * Copyright © 2015 Julien Grall * Copyright © 2013 Spectra Logic Corporation * Copyright © 2018 John Baldwin/The FreeBSD Foundation * Copyright © 2019 Roger Pau Monné/Citrix Systems R&D @@ -32,8 +33,14 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> +#include <sys/systm.h> #include <sys/bus.h> +#include <sys/malloc.h> #include <sys/kernel.h> +#include <sys/limits.h> +#include <sys/lock.h> +#include <sys/mutex.h> +#include <sys/interrupt.h> #include <sys/pcpu.h> #include <sys/proc.h> #include <sys/smp.h> @@ -41,8 +48,8 @@ __FBSDID("$FreeBSD$"); #include <xen/xen-os.h> #include <xen/xen_intr.h> +#include <machine/xen/arch-intr.h> -#include <x86/intr_machdep.h> #include <x86/apicvar.h> /************************ Xen x86 interrupt interface ************************/ @@ -101,3 +108,165 @@ xen_arch_intr_handle_upcall(struct trapframe *trap_frame) critical_exit(); } + +/******************************** EVTCHN PIC *********************************/ + +static void +xen_intr_pic_enable_source(struct intsrc *isrc) +{ + + _Static_assert(offsetof(struct xenisrc, xi_arch.intsrc) == 0, + "xi_arch MUST be at top of xenisrc for x86"); + xen_intr_enable_source((struct xenisrc *)isrc); +} + +/* + * Perform any necessary end-of-interrupt acknowledgements. + * + * \param isrc The interrupt source to EOI. + */ +static void +xen_intr_pic_disable_source(struct intsrc *isrc, int eoi) +{ + + _Static_assert(offsetof(struct xenisrc, xi_arch.intsrc) == 0, + "xi_arch MUST be at top of xenisrc for x86"); + xen_intr_disable_source((struct xenisrc *)isrc); +} + +static void +xen_intr_pic_eoi_source(struct intsrc *isrc) +{ + + /* Nothing to do on end-of-interrupt */ +} + +static void +xen_intr_pic_enable_intr(struct intsrc *isrc) +{ + + _Static_assert(offsetof(struct xenisrc, xi_arch.intsrc) == 0, + "xi_arch MUST be at top of xenisrc for x86"); + xen_intr_enable_intr((struct xenisrc *)isrc); +} + +static void +xen_intr_pic_disable_intr(struct intsrc *isrc) +{ + + _Static_assert(offsetof(struct xenisrc, xi_arch.intsrc) == 0, + "xi_arch MUST be at top of xenisrc for x86"); + 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) +{ + + _Static_assert(offsetof(struct xenisrc, xi_arch.intsrc) == 0, + "xi_arch MUST be at top of xenisrc for x86"); + + return (((struct xenisrc *)isrc)->xi_arch.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); +} + +/** + * Prepare this PIC for system suspension. + */ +static void +xen_intr_pic_suspend(struct pic *pic) +{ + + /* Nothing to do on suspend */ +} + +static void +xen_intr_pic_resume(struct pic *pic, bool suspend_cancelled) +{ + + if (!suspend_cancelled) + xen_intr_resume(); +} + +/** + * 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) +{ + + _Static_assert(offsetof(struct xenisrc, xi_arch.intsrc) == 0, + "xi_arch MUST be at top of xenisrc for x86"); + 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) +{ + int error; + + error = intr_register_pic(&xen_intr_pic); + if (error != 0) + panic("%s(): failed registering Xen/x86 PIC, error=%d\n", + __func__, error); +} diff --git a/sys/x86/xen/xen_intr.c b/sys/x86/xen/xen_intr.c index ec5b8b4c6c9b..ebce27816539 100644 --- a/sys/x86/xen/xen_intr.c +++ b/sys/x86/xen/xen_intr.c @@ -117,37 +117,6 @@ DPCPU_DECLARE(struct vcpu_info *, vcpu_info); #define INVALID_EVTCHN (~(evtchn_port_t)0) /* Invalid event channel */ #define is_valid_evtchn(x) ((uintmax_t)(x) < NR_EVENT_CHANNELS) -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); -static int xen_intr_pic_assign_cpu(struct intsrc *isrc, u_int apic_id); - -/** - * 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_pic_assign_cpu, -}; - /* * Lock for interrupt core data. * @@ -413,8 +382,7 @@ xen_intr_bind_isrc(struct xenisrc **isrcp, evtchn_port_t local_port, * unless specified otherwise, so shuffle them to balance * the interrupt load. */ - xen_intr_assign_cpu(&isrc->xi_arch.intsrc, - apic_cpuid(intr_next_cpu(0))); + xen_intr_assign_cpu(isrc, apic_cpuid(intr_next_cpu(0))); } #endif @@ -544,8 +512,7 @@ xen_intr_handle_upcall(void *unused __unused) ("Received unexpected event on vCPU#%u, event bound to vCPU#%u", PCPU_GET(cpuid), isrc->xi_cpu)); - intr_execute_handlers(&isrc->xi_arch.intsrc, - trap_frame); + xen_arch_intr_execute_handlers(isrc, trap_frame); /* * If this is the final port processed, @@ -609,7 +576,7 @@ xen_intr_init(void *dummy __unused) for (i = 0; i < nitems(s->evtchn_mask); i++) atomic_store_rel_long(&s->evtchn_mask[i], ~0); - intr_register_pic(&xen_intr_pic); + xen_arch_intr_init(); if (bootverbose) printf("Xen interrupt system initialized\n"); @@ -629,13 +596,6 @@ xen_intr_alloc_irqs(void) } /*--------------------------- Common PIC Functions ---------------------------*/ -/** - * Prepare this PIC for system suspension. - */ -static void -xen_intr_suspend(struct pic *unused) -{ -} static void xen_rebind_ipi(struct xenisrc *isrc) @@ -699,7 +659,7 @@ xen_intr_rebind_isrc(struct xenisrc *isrc) #ifdef SMP isrc->xi_cpu = 0; - error = xen_intr_assign_cpu(&isrc->xi_arch.intsrc, cpu); + error = xen_intr_assign_cpu(isrc, cpu); if (error) panic("%s(): unable to rebind Xen channel %u to vCPU%u: %d", __func__, isrc->xi_port, cpu, error); @@ -713,16 +673,13 @@ xen_intr_rebind_isrc(struct xenisrc *isrc) /** * Return this PIC to service after being suspended. */ -static void -xen_intr_resume(struct pic *unused, bool suspend_cancelled) +void +xen_intr_resume(void) { shared_info_t *s = HYPERVISOR_shared_info; u_int isrc_idx; int i; - if (suspend_cancelled) - return; - /* Reset the per-CPU masks */ CPU_FOREACH(i) { struct xen_intr_pcpu_data *pcpu; @@ -767,65 +724,13 @@ xen_intr_resume(struct pic *unused, bool suspend_cancelled) * * \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; 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; - - return (isrc->xi_arch.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. * @@ -834,12 +739,11 @@ xen_intr_config_intr(struct intsrc *isrc, enum intr_trigger trig, * * \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 = XEN_CPUID_TO_VCPUID(to_cpu); int error, masked; @@ -847,7 +751,6 @@ xen_intr_assign_cpu(struct intsrc *base_isrc, u_int to_cpu) return (EOPNOTSUPP); mtx_lock(&xen_intr_isrc_lock); - isrc = (struct xenisrc *)base_isrc; if (!is_valid_evtchn(isrc->xi_port)) { mtx_unlock(&xen_intr_isrc_lock); return (EINVAL); @@ -894,28 +797,15 @@ out: #endif } -/* Wrapper of xen_intr_assign_cpu to use as pic callbacks */ -static int -xen_intr_pic_assign_cpu(struct intsrc *isrc, u_int apic_id) -{ - - return (xen_intr_assign_cpu(isrc, apic_cpuid(apic_id))); -} - /*------------------- Virtual Interrupt Source PIC Functions -----------------*/ /* * 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. */ -static void -xen_intr_disable_source(struct intsrc *base_isrc, int eoi) +void +xen_intr_disable_source(struct xenisrc *isrc) { - struct xenisrc *isrc; - - isrc = (struct xenisrc *)base_isrc; /* * NB: checking if the event channel is already masked is @@ -933,36 +823,22 @@ xen_intr_disable_source(struct intsrc *base_isrc, int eoi) * * \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; - - isrc = (struct xenisrc *)base_isrc; if (isrc->xi_masked == 0) evtchn_unmask_port(isrc->xi_port); } -/* - * Perform any necessary end-of-interrupt acknowledgements. - * - * \param isrc The interrupt source to EOI. - */ -static void -xen_intr_eoi_source(struct intsrc *base_isrc) -{ -} - /* * Enable and unmask the interrupt source. * * \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; evtchn_unmask_port(isrc->xi_port); } @@ -1091,7 +967,7 @@ xen_intr_bind_virq(device_t dev, u_int virq, u_int cpu, #ifdef SMP if (error == 0) - error = intr_event_bind(isrc->xi_arch.intsrc.is_event, cpu); + error = xen_arch_intr_event_bind(isrc, cpu); #endif if (error != 0) { @@ -1111,7 +987,7 @@ xen_intr_bind_virq(device_t dev, u_int virq, u_int cpu, * masks manually so events can't fire on the wrong cpu * during AP startup. */ - xen_intr_assign_cpu(&isrc->xi_arch.intsrc, cpu); + xen_intr_assign_cpu(isrc, cpu); } #endif @@ -1167,7 +1043,7 @@ xen_intr_alloc_and_bind_ipi(u_int cpu, driver_filter_t filter, * masks manually so events can't fire on the wrong cpu * during AP startup. */ - xen_intr_assign_cpu(&isrc->xi_arch.intsrc, cpu); + xen_intr_assign_cpu(isrc, cpu); } /* @@ -1195,7 +1071,7 @@ xen_intr_describe(xen_intr_handle_t port_handle, const char *fmt, ...) va_start(ap, fmt); vsnprintf(descr, sizeof(descr), fmt, ap); va_end(ap); - return (intr_describe(isrc->xi_arch.vector, isrc->xi_cookie, descr)); + return (xen_arch_intr_describe(isrc, isrc->xi_cookie, descr)); } void @@ -1219,7 +1095,7 @@ xen_intr_unbind(xen_intr_handle_t *port_handlep) mtx_unlock(&xen_intr_isrc_lock); if (isrc->xi_cookie != NULL) - intr_remove_handler(isrc->xi_cookie); + xen_arch_intr_remove_handler(isrc, isrc->xi_cookie); xen_intr_release_isrc(isrc); } @@ -1262,8 +1138,8 @@ xen_intr_add_handler(const char *name, driver_filter_t filter, if (isrc == NULL || isrc->xi_cookie != NULL) return (EINVAL); - error = intr_add_handler(name, isrc->xi_arch.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);