xref: /freebsd/sys/dev/xen/bus/xen_intr.c (revision c880f12f5ac6b1fe8b188e08862e8da829533fdb)
15e2183daSJulien Grall /******************************************************************************
25e2183daSJulien Grall  * xen_intr.c
35e2183daSJulien Grall  *
45e2183daSJulien Grall  * Xen event and interrupt services for x86 HVM guests.
55e2183daSJulien Grall  *
65e2183daSJulien Grall  * Copyright (c) 2002-2005, K A Fraser
75e2183daSJulien Grall  * Copyright (c) 2005, Intel Corporation <xiaofeng.ling@intel.com>
85e2183daSJulien Grall  * Copyright (c) 2012, Spectra Logic Corporation
95e2183daSJulien Grall  * Copyright © 2021-2023, Elliott Mitchell
105e2183daSJulien Grall  *
115e2183daSJulien Grall  * This file may be distributed separately from the Linux kernel, or
125e2183daSJulien Grall  * incorporated into other software packages, subject to the following license:
135e2183daSJulien Grall  *
145e2183daSJulien Grall  * Permission is hereby granted, free of charge, to any person obtaining a copy
155e2183daSJulien Grall  * of this source file (the "Software"), to deal in the Software without
165e2183daSJulien Grall  * restriction, including without limitation the rights to use, copy, modify,
175e2183daSJulien Grall  * merge, publish, distribute, sublicense, and/or sell copies of the Software,
185e2183daSJulien Grall  * and to permit persons to whom the Software is furnished to do so, subject to
195e2183daSJulien Grall  * the following conditions:
205e2183daSJulien Grall  *
215e2183daSJulien Grall  * The above copyright notice and this permission notice shall be included in
225e2183daSJulien Grall  * all copies or substantial portions of the Software.
235e2183daSJulien Grall  *
245e2183daSJulien Grall  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
255e2183daSJulien Grall  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
265e2183daSJulien Grall  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
275e2183daSJulien Grall  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
285e2183daSJulien Grall  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
295e2183daSJulien Grall  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
305e2183daSJulien Grall  * IN THE SOFTWARE.
315e2183daSJulien Grall  */
325e2183daSJulien Grall 
335e2183daSJulien Grall #include <sys/cdefs.h>
345e2183daSJulien Grall #include "opt_ddb.h"
355e2183daSJulien Grall 
365e2183daSJulien Grall #include <sys/param.h>
375e2183daSJulien Grall #include <sys/systm.h>
385e2183daSJulien Grall #include <sys/bus.h>
395e2183daSJulien Grall #include <sys/kernel.h>
405e2183daSJulien Grall #include <sys/limits.h>
415e2183daSJulien Grall #include <sys/lock.h>
425e2183daSJulien Grall #include <sys/mutex.h>
435e2183daSJulien Grall #include <sys/interrupt.h>
445e2183daSJulien Grall #include <sys/pcpu.h>
455e2183daSJulien Grall #include <sys/proc.h>
465e2183daSJulien Grall #include <sys/smp.h>
475e2183daSJulien Grall #include <sys/refcount.h>
485e2183daSJulien Grall 
495e2183daSJulien Grall #include <vm/vm.h>
505e2183daSJulien Grall #include <vm/pmap.h>
515e2183daSJulien Grall 
525e2183daSJulien Grall #include <machine/smp.h>
535e2183daSJulien Grall #include <machine/stdarg.h>
545e2183daSJulien Grall 
555e2183daSJulien Grall #include <xen/xen-os.h>
565e2183daSJulien Grall #include <xen/hypervisor.h>
575e2183daSJulien Grall #include <xen/xen_intr.h>
585e2183daSJulien Grall #include <xen/evtchn/evtchnvar.h>
595e2183daSJulien Grall 
605e2183daSJulien Grall #include <dev/xen/xenpci/xenpcivar.h>
615e2183daSJulien Grall #include <dev/pci/pcivar.h>
625e2183daSJulien Grall #include <machine/xen/arch-intr.h>
635e2183daSJulien Grall 
645e2183daSJulien Grall #ifdef DDB
655e2183daSJulien Grall #include <ddb/ddb.h>
665e2183daSJulien Grall #endif
675e2183daSJulien Grall 
685e2183daSJulien Grall /**
695e2183daSJulien Grall  * Per-cpu event channel processing state.
705e2183daSJulien Grall  */
715e2183daSJulien Grall struct xen_intr_pcpu_data {
725e2183daSJulien Grall 	/**
735e2183daSJulien Grall 	 * The last event channel bitmap section (level one bit) processed.
745e2183daSJulien Grall 	 * This is used to ensure we scan all ports before
755e2183daSJulien Grall 	 * servicing an already servied port again.
765e2183daSJulien Grall 	 */
775e2183daSJulien Grall 	u_int	last_processed_l1i;
785e2183daSJulien Grall 
795e2183daSJulien Grall 	/**
805e2183daSJulien Grall 	 * The last event channel processed within the event channel
815e2183daSJulien Grall 	 * bitmap being scanned.
825e2183daSJulien Grall 	 */
835e2183daSJulien Grall 	u_int	last_processed_l2i;
845e2183daSJulien Grall 
855e2183daSJulien Grall 	/**
865e2183daSJulien Grall 	 * A bitmap of ports that can be serviced from this CPU.
875e2183daSJulien Grall 	 * A set bit means interrupt handling is enabled.
885e2183daSJulien Grall 	 */
895e2183daSJulien Grall 	u_long	evtchn_enabled[sizeof(u_long) * 8];
905e2183daSJulien Grall };
915e2183daSJulien Grall 
925e2183daSJulien Grall /*
935e2183daSJulien Grall  * Start the scan at port 0 by initializing the last scanned
945e2183daSJulien Grall  * location as the highest numbered event channel port.
955e2183daSJulien Grall  */
965e2183daSJulien Grall DPCPU_DEFINE_STATIC(struct xen_intr_pcpu_data, xen_intr_pcpu) = {
975e2183daSJulien Grall 	.last_processed_l1i = LONG_BIT - 1,
985e2183daSJulien Grall 	.last_processed_l2i = LONG_BIT - 1
995e2183daSJulien Grall };
1005e2183daSJulien Grall 
1015e2183daSJulien Grall DPCPU_DECLARE(struct vcpu_info *, vcpu_info);
1025e2183daSJulien Grall 
1035e2183daSJulien Grall #define	INVALID_EVTCHN		(~(evtchn_port_t)0) /* Invalid event channel */
1045e2183daSJulien Grall #define	is_valid_evtchn(x)	((uintmax_t)(x) < NR_EVENT_CHANNELS)
1055e2183daSJulien Grall 
1065e2183daSJulien Grall /*
1075e2183daSJulien Grall  * Lock for interrupt core data.
1085e2183daSJulien Grall  *
1095e2183daSJulien Grall  * Modifying xen_intr_port_to_isrc[], or isrc->xi_port (implies the former)
1105e2183daSJulien Grall  * requires this lock be held.  Any time this lock is not held, the condition
1115e2183daSJulien Grall  * `!xen_intr_port_to_isrc[i] || (xen_intr_port_to_isrc[i]->ix_port == i)`
1125e2183daSJulien Grall  * MUST be true for all values of i which are valid indicies of the array.
1135e2183daSJulien Grall  *
1145e2183daSJulien Grall  * Acquire/release operations for isrc->xi_refcount require this lock be held.
1155e2183daSJulien Grall  */
1165e2183daSJulien Grall static struct mtx	 xen_intr_isrc_lock;
1175e2183daSJulien Grall static struct xenisrc	*xen_intr_port_to_isrc[NR_EVENT_CHANNELS];
1185e2183daSJulien Grall 
1195e2183daSJulien Grall /*------------------------- Private Functions --------------------------------*/
1205e2183daSJulien Grall 
1215e2183daSJulien Grall /**
1225e2183daSJulien Grall  * Retrieve a handle for a Xen interrupt source.
1235e2183daSJulien Grall  *
1245e2183daSJulien Grall  * \param isrc  A valid Xen interrupt source structure.
1255e2183daSJulien Grall  *
1265e2183daSJulien Grall  * \returns  A handle suitable for use with xen_intr_isrc_from_handle()
1275e2183daSJulien Grall  *           to retrieve the original Xen interrupt source structure.
1285e2183daSJulien Grall  */
1295e2183daSJulien Grall 
1305e2183daSJulien Grall static inline xen_intr_handle_t
1315e2183daSJulien Grall xen_intr_handle_from_isrc(struct xenisrc *isrc)
1325e2183daSJulien Grall {
1335e2183daSJulien Grall 	return (isrc);
1345e2183daSJulien Grall }
1355e2183daSJulien Grall 
1365e2183daSJulien Grall /**
1375e2183daSJulien Grall  * Lookup a Xen interrupt source object given an interrupt binding handle.
1385e2183daSJulien Grall  *
1395e2183daSJulien Grall  * \param handle  A handle initialized by a previous call to
1405e2183daSJulien Grall  *                xen_intr_bind_isrc().
1415e2183daSJulien Grall  *
1425e2183daSJulien Grall  * \returns  A pointer to the Xen interrupt source object associated
1435e2183daSJulien Grall  *           with the given interrupt handle.  NULL if no association
1445e2183daSJulien Grall  *           currently exists.
1455e2183daSJulien Grall  */
1465e2183daSJulien Grall static inline struct xenisrc *
1475e2183daSJulien Grall xen_intr_isrc_from_handle(xen_intr_handle_t handle)
1485e2183daSJulien Grall {
1495e2183daSJulien Grall 	return ((struct xenisrc *)handle);
1505e2183daSJulien Grall }
1515e2183daSJulien Grall 
1525e2183daSJulien Grall /**
1535e2183daSJulien Grall  * Disable signal delivery for an event channel port on the
1545e2183daSJulien Grall  * specified CPU.
1555e2183daSJulien Grall  *
1565e2183daSJulien Grall  * \param port  The event channel port to mask.
1575e2183daSJulien Grall  *
1585e2183daSJulien Grall  * This API is used to manage the port<=>CPU binding of event
1595e2183daSJulien Grall  * channel handlers.
1605e2183daSJulien Grall  *
1615e2183daSJulien Grall  * \note  This operation does not preclude reception of an event
1625e2183daSJulien Grall  *        for this event channel on another CPU.  To mask the
1635e2183daSJulien Grall  *        event channel globally, use evtchn_mask().
1645e2183daSJulien Grall  */
1655e2183daSJulien Grall static inline void
1665e2183daSJulien Grall evtchn_cpu_mask_port(u_int cpu, evtchn_port_t port)
1675e2183daSJulien Grall {
1685e2183daSJulien Grall 	struct xen_intr_pcpu_data *pcpu;
1695e2183daSJulien Grall 
1705e2183daSJulien Grall 	pcpu = DPCPU_ID_PTR(cpu, xen_intr_pcpu);
1715e2183daSJulien Grall 	xen_clear_bit(port, pcpu->evtchn_enabled);
1725e2183daSJulien Grall }
1735e2183daSJulien Grall 
1745e2183daSJulien Grall /**
1755e2183daSJulien Grall  * Enable signal delivery for an event channel port on the
1765e2183daSJulien Grall  * specified CPU.
1775e2183daSJulien Grall  *
1785e2183daSJulien Grall  * \param port  The event channel port to unmask.
1795e2183daSJulien Grall  *
1805e2183daSJulien Grall  * This API is used to manage the port<=>CPU binding of event
1815e2183daSJulien Grall  * channel handlers.
1825e2183daSJulien Grall  *
1835e2183daSJulien Grall  * \note  This operation does not guarantee that event delivery
1845e2183daSJulien Grall  *        is enabled for this event channel port.  The port must
1855e2183daSJulien Grall  *        also be globally enabled.  See evtchn_unmask().
1865e2183daSJulien Grall  */
1875e2183daSJulien Grall static inline void
1885e2183daSJulien Grall evtchn_cpu_unmask_port(u_int cpu, evtchn_port_t port)
1895e2183daSJulien Grall {
1905e2183daSJulien Grall 	struct xen_intr_pcpu_data *pcpu;
1915e2183daSJulien Grall 
1925e2183daSJulien Grall 	pcpu = DPCPU_ID_PTR(cpu, xen_intr_pcpu);
1935e2183daSJulien Grall 	xen_set_bit(port, pcpu->evtchn_enabled);
1945e2183daSJulien Grall }
1955e2183daSJulien Grall 
1965e2183daSJulien Grall /**
1975e2183daSJulien Grall  * Attempt to free an active Xen interrupt source object.
1985e2183daSJulien Grall  *
1995e2183daSJulien Grall  * \param isrc  The interrupt source object to release.
2005e2183daSJulien Grall  *
2015e2183daSJulien Grall  * \returns  EBUSY if the source is still in use, otherwise 0.
2025e2183daSJulien Grall  */
2035e2183daSJulien Grall static int
2045e2183daSJulien Grall xen_intr_release_isrc(struct xenisrc *isrc)
2055e2183daSJulien Grall {
2065e2183daSJulien Grall 
2075e2183daSJulien Grall 	mtx_lock(&xen_intr_isrc_lock);
2085e2183daSJulien Grall 	if (is_valid_evtchn(isrc->xi_port)) {
2095e2183daSJulien Grall 		evtchn_mask_port(isrc->xi_port);
2105e2183daSJulien Grall 		evtchn_clear_port(isrc->xi_port);
2115e2183daSJulien Grall 
2125e2183daSJulien Grall 		/* Rebind port to CPU 0. */
2135e2183daSJulien Grall 		evtchn_cpu_mask_port(isrc->xi_cpu, isrc->xi_port);
2145e2183daSJulien Grall 		evtchn_cpu_unmask_port(0, isrc->xi_port);
2155e2183daSJulien Grall 
2165e2183daSJulien Grall 		if (isrc->xi_close != 0) {
2175e2183daSJulien Grall 			struct evtchn_close close = { .port = isrc->xi_port };
2185e2183daSJulien Grall 
2195e2183daSJulien Grall 			if (HYPERVISOR_event_channel_op(EVTCHNOP_close, &close))
2205e2183daSJulien Grall 				panic("EVTCHNOP_close failed");
2215e2183daSJulien Grall 		}
2225e2183daSJulien Grall 
2235e2183daSJulien Grall 		xen_intr_port_to_isrc[isrc->xi_port] = NULL;
2245e2183daSJulien Grall 	}
2255e2183daSJulien Grall 	/* not reachable from xen_intr_port_to_isrc[], unlock */
2265e2183daSJulien Grall 	mtx_unlock(&xen_intr_isrc_lock);
2275e2183daSJulien Grall 
2285e2183daSJulien Grall 	xen_arch_intr_release(isrc);
2295e2183daSJulien Grall 	return (0);
2305e2183daSJulien Grall }
2315e2183daSJulien Grall 
2325e2183daSJulien Grall /**
2335e2183daSJulien Grall  * Associate an interrupt handler with an already allocated local Xen
2345e2183daSJulien Grall  * event channel port.
2355e2183daSJulien Grall  *
2365e2183daSJulien Grall  * \param isrcp       The returned Xen interrupt object associated with
2375e2183daSJulien Grall  *                    the specified local port.
2385e2183daSJulien Grall  * \param local_port  The event channel to bind.
2395e2183daSJulien Grall  * \param type        The event channel type of local_port.
2405e2183daSJulien Grall  * \param intr_owner  The device making this bind request.
2415e2183daSJulien Grall  * \param filter      An interrupt filter handler.  Specify NULL
2425e2183daSJulien Grall  *                    to always dispatch to the ithread handler.
2435e2183daSJulien Grall  * \param handler     An interrupt ithread handler.  Optional (can
2445e2183daSJulien Grall  *                    specify NULL) if all necessary event actions
2455e2183daSJulien Grall  *                    are performed by filter.
2465e2183daSJulien Grall  * \param arg         Argument to present to both filter and handler.
2475e2183daSJulien Grall  * \param irqflags    Interrupt handler flags.  See sys/bus.h.
2485e2183daSJulien Grall  * \param handlep     Pointer to an opaque handle used to manage this
2495e2183daSJulien Grall  *                    registration.
2505e2183daSJulien Grall  *
2515e2183daSJulien Grall  * \returns  0 on success, otherwise an errno.
2525e2183daSJulien Grall  */
2535e2183daSJulien Grall static int
2545e2183daSJulien Grall xen_intr_bind_isrc(struct xenisrc **isrcp, evtchn_port_t local_port,
2555e2183daSJulien Grall     enum evtchn_type type, const char *intr_owner, driver_filter_t filter,
2565e2183daSJulien Grall     driver_intr_t handler, void *arg, enum intr_type flags,
2575e2183daSJulien Grall     xen_intr_handle_t *const port_handlep)
2585e2183daSJulien Grall {
2595e2183daSJulien Grall 	struct xenisrc *isrc;
2605e2183daSJulien Grall 	int error;
2615e2183daSJulien Grall 
2625e2183daSJulien Grall 	*isrcp = NULL;
2635e2183daSJulien Grall 	if (port_handlep == NULL) {
2645e2183daSJulien Grall 		printf("%s: %s: Bad event handle\n", intr_owner, __func__);
2655e2183daSJulien Grall 		return (EINVAL);
2665e2183daSJulien Grall 	}
2675e2183daSJulien Grall 	*port_handlep = NULL;
2685e2183daSJulien Grall 
2695e2183daSJulien Grall 	isrc = xen_arch_intr_alloc();
2705e2183daSJulien Grall 	if (isrc == NULL)
2715e2183daSJulien Grall 		return (ENOSPC);
2725e2183daSJulien Grall 
2735e2183daSJulien Grall 	isrc->xi_cookie = NULL;
2745e2183daSJulien Grall 	isrc->xi_type = type;
2755e2183daSJulien Grall 	isrc->xi_port = local_port;
2765e2183daSJulien Grall 	isrc->xi_close = false;
2775e2183daSJulien Grall 	isrc->xi_cpu = 0;
2785e2183daSJulien Grall 	refcount_init(&isrc->xi_refcount, 1);
2795e2183daSJulien Grall 	mtx_lock(&xen_intr_isrc_lock);
2805e2183daSJulien Grall 	xen_intr_port_to_isrc[isrc->xi_port] = isrc;
2815e2183daSJulien Grall 	mtx_unlock(&xen_intr_isrc_lock);
2825e2183daSJulien Grall 
2835e2183daSJulien Grall #ifdef SMP
2845e2183daSJulien Grall 	if (type == EVTCHN_TYPE_PORT) {
2855e2183daSJulien Grall 		/*
2865e2183daSJulien Grall 		 * By default all interrupts are assigned to vCPU#0
2875e2183daSJulien Grall 		 * unless specified otherwise, so shuffle them to balance
2885e2183daSJulien Grall 		 * the interrupt load.
2895e2183daSJulien Grall 		 */
2905e2183daSJulien Grall 		xen_intr_assign_cpu(isrc, xen_arch_intr_next_cpu(isrc));
2915e2183daSJulien Grall 	}
2925e2183daSJulien Grall #endif
2935e2183daSJulien Grall 
2945e2183daSJulien Grall 	/*
2955e2183daSJulien Grall 	 * If a filter or handler function is provided, add it to the event.
2965e2183daSJulien Grall 	 * Otherwise the event channel is left masked and without a handler,
2975e2183daSJulien Grall 	 * the caller is in charge of setting that up.
2985e2183daSJulien Grall 	 */
2995e2183daSJulien Grall 	if (filter != NULL || handler != NULL) {
3005e2183daSJulien Grall 		error = xen_intr_add_handler(intr_owner, filter, handler, arg,
3015e2183daSJulien Grall 		    flags, xen_intr_handle_from_isrc(isrc));
3025e2183daSJulien Grall 		if (error != 0) {
3035e2183daSJulien Grall 			xen_intr_release_isrc(isrc);
3045e2183daSJulien Grall 			return (error);
3055e2183daSJulien Grall 		}
3065e2183daSJulien Grall 	}
3075e2183daSJulien Grall 
3085e2183daSJulien Grall 	*isrcp = isrc;
3095e2183daSJulien Grall 	/* Assign the opaque handler */
3105e2183daSJulien Grall 	*port_handlep = xen_intr_handle_from_isrc(isrc);
3115e2183daSJulien Grall 	return (0);
3125e2183daSJulien Grall }
3135e2183daSJulien Grall 
3145e2183daSJulien Grall /**
3155e2183daSJulien Grall  * Determine the event channel ports at the given section of the
3165e2183daSJulien Grall  * event port bitmap which have pending events for the given cpu.
3175e2183daSJulien Grall  *
3185e2183daSJulien Grall  * \param pcpu  The Xen interrupt pcpu data for the cpu being queried.
3195e2183daSJulien Grall  * \param sh    The Xen shared info area.
3205e2183daSJulien Grall  * \param idx   The index of the section of the event channel bitmap to
3215e2183daSJulien Grall  *              inspect.
3225e2183daSJulien Grall  *
3235e2183daSJulien Grall  * \returns  A u_long with bits set for every event channel with pending
3245e2183daSJulien Grall  *           events.
3255e2183daSJulien Grall  */
3265e2183daSJulien Grall static inline u_long
3275e2183daSJulien Grall xen_intr_active_ports(const struct xen_intr_pcpu_data *const pcpu,
3285e2183daSJulien Grall     const u_int idx)
3295e2183daSJulien Grall {
3305e2183daSJulien Grall 	volatile const shared_info_t *const sh = HYPERVISOR_shared_info;
3315e2183daSJulien Grall 
3325e2183daSJulien Grall 	CTASSERT(sizeof(sh->evtchn_mask[0]) == sizeof(sh->evtchn_pending[0]));
3335e2183daSJulien Grall 	CTASSERT(sizeof(sh->evtchn_mask[0]) == sizeof(pcpu->evtchn_enabled[0]));
3345e2183daSJulien Grall 	CTASSERT(sizeof(sh->evtchn_mask) == sizeof(sh->evtchn_pending));
3355e2183daSJulien Grall 	CTASSERT(sizeof(sh->evtchn_mask) == sizeof(pcpu->evtchn_enabled));
3365e2183daSJulien Grall 	return (sh->evtchn_pending[idx]
3375e2183daSJulien Grall 	      & ~sh->evtchn_mask[idx]
3385e2183daSJulien Grall 	      & pcpu->evtchn_enabled[idx]);
3395e2183daSJulien Grall }
3405e2183daSJulien Grall 
3415e2183daSJulien Grall /**
3425e2183daSJulien Grall  * Interrupt handler for processing all Xen event channel events.
3435e2183daSJulien Grall  *
3445e2183daSJulien Grall  * \param trap_frame  The trap frame context for the current interrupt.
3455e2183daSJulien Grall  */
3465e2183daSJulien Grall int
3475e2183daSJulien Grall xen_intr_handle_upcall(void *unused __unused)
3485e2183daSJulien Grall {
3495e2183daSJulien Grall 	struct trapframe *trap_frame = curthread->td_intr_frame;
3505e2183daSJulien Grall 	u_int l1i, l2i, port, cpu __diagused;
3515e2183daSJulien Grall 	u_long masked_l1, masked_l2;
3525e2183daSJulien Grall 	struct xenisrc *isrc;
3535e2183daSJulien Grall 	vcpu_info_t *v;
3545e2183daSJulien Grall 	struct xen_intr_pcpu_data *pc;
3555e2183daSJulien Grall 	u_long l1, l2;
3565e2183daSJulien Grall 
3575e2183daSJulien Grall 	/* We must remain on the same vCPU during this function */
3585e2183daSJulien Grall 	CRITICAL_ASSERT(curthread);
3595e2183daSJulien Grall 
3605e2183daSJulien Grall 	cpu = PCPU_GET(cpuid);
3615e2183daSJulien Grall 	pc  = DPCPU_PTR(xen_intr_pcpu);
3625e2183daSJulien Grall 	v   = DPCPU_GET(vcpu_info);
3635e2183daSJulien Grall 
3645e2183daSJulien Grall 	if (!xen_has_percpu_evtchn()) {
3655e2183daSJulien Grall 		KASSERT((cpu == 0), ("Fired PCI event callback on wrong CPU"));
3665e2183daSJulien Grall 	}
3675e2183daSJulien Grall 
3685e2183daSJulien Grall 	v->evtchn_upcall_pending = 0;
3695e2183daSJulien Grall /* No need for a barrier on x86 -- XCHG is a barrier on x86. */
3705e2183daSJulien Grall #if !defined(__amd64__) && !defined(__i386__)
3715e2183daSJulien Grall 	/* Clear master flag /before/ clearing selector flag. */
3725e2183daSJulien Grall 	wmb();
3735e2183daSJulien Grall #endif
3745e2183daSJulien Grall 	l1 = atomic_readandclear_long(&v->evtchn_pending_sel);
3755e2183daSJulien Grall 
3765e2183daSJulien Grall 	l1i = pc->last_processed_l1i;
3775e2183daSJulien Grall 	l2i = pc->last_processed_l2i;
3785e2183daSJulien Grall 
3795e2183daSJulien Grall 	while (l1 != 0) {
3805e2183daSJulien Grall 		l1i = (l1i + 1) % LONG_BIT;
3815e2183daSJulien Grall 		masked_l1 = l1 & ((~0UL) << l1i);
3825e2183daSJulien Grall 
3835e2183daSJulien Grall 		if (masked_l1 == 0) {
3845e2183daSJulien Grall 			/*
3855e2183daSJulien Grall 			 * if we masked out all events, wrap around
3865e2183daSJulien Grall 			 * to the beginning.
3875e2183daSJulien Grall 			 */
3885e2183daSJulien Grall 			l1i = LONG_BIT - 1;
3895e2183daSJulien Grall 			l2i = LONG_BIT - 1;
3905e2183daSJulien Grall 			continue;
3915e2183daSJulien Grall 		}
3925e2183daSJulien Grall 		l1i = ffsl(masked_l1) - 1;
3935e2183daSJulien Grall 
3945e2183daSJulien Grall 		do {
3955e2183daSJulien Grall 			l2 = xen_intr_active_ports(pc, l1i);
3965e2183daSJulien Grall 
3975e2183daSJulien Grall 			l2i = (l2i + 1) % LONG_BIT;
3985e2183daSJulien Grall 			masked_l2 = l2 & ((~0UL) << l2i);
3995e2183daSJulien Grall 
4005e2183daSJulien Grall 			if (masked_l2 == 0) {
4015e2183daSJulien Grall 				/* if we masked out all events, move on */
4025e2183daSJulien Grall 				l2i = LONG_BIT - 1;
4035e2183daSJulien Grall 				break;
4045e2183daSJulien Grall 			}
4055e2183daSJulien Grall 			l2i = ffsl(masked_l2) - 1;
4065e2183daSJulien Grall 
4075e2183daSJulien Grall 			/* process port */
4085e2183daSJulien Grall 			port = (l1i * LONG_BIT) + l2i;
4095e2183daSJulien Grall 			evtchn_clear_port(port);
4105e2183daSJulien Grall 
4115e2183daSJulien Grall 			isrc = xen_intr_port_to_isrc[port];
4125e2183daSJulien Grall 			if (__predict_false(isrc == NULL))
4135e2183daSJulien Grall 				continue;
4145e2183daSJulien Grall 
4155e2183daSJulien Grall 			/* Make sure we are firing on the right vCPU */
4165e2183daSJulien Grall 			KASSERT((isrc->xi_cpu == PCPU_GET(cpuid)),
4175e2183daSJulien Grall 				("Received unexpected event on vCPU#%u, event bound to vCPU#%u",
4185e2183daSJulien Grall 				PCPU_GET(cpuid), isrc->xi_cpu));
4195e2183daSJulien Grall 
4205e2183daSJulien Grall 			xen_arch_intr_execute_handlers(isrc, trap_frame);
4215e2183daSJulien Grall 
4225e2183daSJulien Grall 			/*
4235e2183daSJulien Grall 			 * If this is the final port processed,
4245e2183daSJulien Grall 			 * we'll pick up here+1 next time.
4255e2183daSJulien Grall 			 */
4265e2183daSJulien Grall 			pc->last_processed_l1i = l1i;
4275e2183daSJulien Grall 			pc->last_processed_l2i = l2i;
4285e2183daSJulien Grall 
4295e2183daSJulien Grall 		} while (l2i != LONG_BIT - 1);
4305e2183daSJulien Grall 
4315e2183daSJulien Grall 		l2 = xen_intr_active_ports(pc, l1i);
4325e2183daSJulien Grall 		if (l2 == 0) {
4335e2183daSJulien Grall 			/*
4345e2183daSJulien Grall 			 * We handled all ports, so we can clear the
4355e2183daSJulien Grall 			 * selector bit.
4365e2183daSJulien Grall 			 */
4375e2183daSJulien Grall 			l1 &= ~(1UL << l1i);
4385e2183daSJulien Grall 		}
4395e2183daSJulien Grall 	}
4405e2183daSJulien Grall 
4415e2183daSJulien Grall 	return (FILTER_HANDLED);
4425e2183daSJulien Grall }
4435e2183daSJulien Grall 
4445e2183daSJulien Grall static int
4455e2183daSJulien Grall xen_intr_init(void *dummy __unused)
4465e2183daSJulien Grall {
4475e2183daSJulien Grall 	shared_info_t *s = HYPERVISOR_shared_info;
4485e2183daSJulien Grall 	struct xen_intr_pcpu_data *pcpu;
4495e2183daSJulien Grall 	int i;
4505e2183daSJulien Grall 
4515e2183daSJulien Grall 	if (!xen_domain())
4525e2183daSJulien Grall 		return (0);
4535e2183daSJulien Grall 
4545e2183daSJulien Grall 	_Static_assert(is_valid_evtchn(0),
4555e2183daSJulien Grall 	    "is_valid_evtchn(0) fails (unused by Xen, but valid by interface");
4565e2183daSJulien Grall 	_Static_assert(is_valid_evtchn(NR_EVENT_CHANNELS - 1),
4575e2183daSJulien Grall 	    "is_valid_evtchn(max) fails (is a valid channel)");
4585e2183daSJulien Grall 	_Static_assert(!is_valid_evtchn(NR_EVENT_CHANNELS),
4595e2183daSJulien Grall 	    "is_valid_evtchn(>max) fails (NOT a valid channel)");
4605e2183daSJulien Grall 	_Static_assert(!is_valid_evtchn(~(evtchn_port_t)0),
4615e2183daSJulien Grall 	    "is_valid_evtchn(maxint) fails (overflow?)");
4625e2183daSJulien Grall 	_Static_assert(!is_valid_evtchn(INVALID_EVTCHN),
4635e2183daSJulien Grall 	    "is_valid_evtchn(INVALID_EVTCHN) fails (must be invalid!)");
4645e2183daSJulien Grall 	_Static_assert(!is_valid_evtchn(-1),
4655e2183daSJulien Grall 	    "is_valid_evtchn(-1) fails (negative are invalid)");
4665e2183daSJulien Grall 
4675e2183daSJulien Grall 	mtx_init(&xen_intr_isrc_lock, "xen-irq-lock", NULL, MTX_DEF);
4685e2183daSJulien Grall 
4695e2183daSJulien Grall 	/*
4705e2183daSJulien Grall 	 * Set the per-cpu mask of CPU#0 to enable all, since by default all
4715e2183daSJulien Grall 	 * event channels are bound to CPU#0.
4725e2183daSJulien Grall 	 */
4735e2183daSJulien Grall 	CPU_FOREACH(i) {
4745e2183daSJulien Grall 		pcpu = DPCPU_ID_PTR(i, xen_intr_pcpu);
4755e2183daSJulien Grall 		memset(pcpu->evtchn_enabled, i == 0 ? ~0 : 0,
4765e2183daSJulien Grall 		    sizeof(pcpu->evtchn_enabled));
4775e2183daSJulien Grall 	}
4785e2183daSJulien Grall 
4795e2183daSJulien Grall 	for (i = 0; i < nitems(s->evtchn_mask); i++)
4805e2183daSJulien Grall 		atomic_store_rel_long(&s->evtchn_mask[i], ~0);
4815e2183daSJulien Grall 
4825e2183daSJulien Grall 	xen_arch_intr_init();
4835e2183daSJulien Grall 
4845e2183daSJulien Grall 	if (bootverbose)
4855e2183daSJulien Grall 		printf("Xen interrupt system initialized\n");
4865e2183daSJulien Grall 
4875e2183daSJulien Grall 	return (0);
4885e2183daSJulien Grall }
4895e2183daSJulien Grall SYSINIT(xen_intr_init, SI_SUB_INTR, SI_ORDER_SECOND, xen_intr_init, NULL);
4905e2183daSJulien Grall 
4915e2183daSJulien Grall /*--------------------------- Common PIC Functions ---------------------------*/
4925e2183daSJulien Grall 
4935e2183daSJulien Grall static void
4945e2183daSJulien Grall xen_rebind_ipi(struct xenisrc *isrc)
4955e2183daSJulien Grall {
4965e2183daSJulien Grall #ifdef SMP
4975e2183daSJulien Grall 	u_int cpu = isrc->xi_cpu;
4985e2183daSJulien Grall 	u_int vcpu_id = XEN_CPUID_TO_VCPUID(cpu);
4995e2183daSJulien Grall 	int error;
5005e2183daSJulien Grall 	struct evtchn_bind_ipi bind_ipi = { .vcpu = vcpu_id };
5015e2183daSJulien Grall 
5025e2183daSJulien Grall 	error = HYPERVISOR_event_channel_op(EVTCHNOP_bind_ipi,
5035e2183daSJulien Grall 	                                    &bind_ipi);
5045e2183daSJulien Grall 	if (error != 0)
5055e2183daSJulien Grall 		panic("unable to rebind xen IPI: %d", error);
5065e2183daSJulien Grall 
5075e2183daSJulien Grall 	isrc->xi_port = bind_ipi.port;
5085e2183daSJulien Grall #else
5095e2183daSJulien Grall 	panic("Resume IPI event channel on UP");
5105e2183daSJulien Grall #endif
5115e2183daSJulien Grall }
5125e2183daSJulien Grall 
5135e2183daSJulien Grall static void
5145e2183daSJulien Grall xen_rebind_virq(struct xenisrc *isrc)
5155e2183daSJulien Grall {
5165e2183daSJulien Grall 	u_int cpu = isrc->xi_cpu;
5175e2183daSJulien Grall 	u_int vcpu_id = XEN_CPUID_TO_VCPUID(cpu);
5185e2183daSJulien Grall 	int error;
5195e2183daSJulien Grall 	struct evtchn_bind_virq bind_virq = { .virq = isrc->xi_virq,
5205e2183daSJulien Grall 	                                      .vcpu = vcpu_id };
5215e2183daSJulien Grall 
5225e2183daSJulien Grall 	error = HYPERVISOR_event_channel_op(EVTCHNOP_bind_virq,
5235e2183daSJulien Grall 	                                    &bind_virq);
5245e2183daSJulien Grall 	if (error != 0)
5255e2183daSJulien Grall 		panic("unable to rebind xen VIRQ#%u: %d", isrc->xi_virq, error);
5265e2183daSJulien Grall 
5275e2183daSJulien Grall 	isrc->xi_port = bind_virq.port;
5285e2183daSJulien Grall }
5295e2183daSJulien Grall 
5305e2183daSJulien Grall static struct xenisrc *
5315e2183daSJulien Grall xen_intr_rebind_isrc(struct xenisrc *isrc)
5325e2183daSJulien Grall {
5335e2183daSJulien Grall #ifdef SMP
5345e2183daSJulien Grall 	u_int cpu = isrc->xi_cpu;
5355e2183daSJulien Grall 	int error;
5365e2183daSJulien Grall #endif
5375e2183daSJulien Grall 	struct xenisrc *prev;
5385e2183daSJulien Grall 
5395e2183daSJulien Grall 	switch (isrc->xi_type) {
5405e2183daSJulien Grall 	case EVTCHN_TYPE_IPI:
5415e2183daSJulien Grall 		xen_rebind_ipi(isrc);
5425e2183daSJulien Grall 		break;
5435e2183daSJulien Grall 	case EVTCHN_TYPE_VIRQ:
5445e2183daSJulien Grall 		xen_rebind_virq(isrc);
5455e2183daSJulien Grall 		break;
5465e2183daSJulien Grall 	default:
5475e2183daSJulien Grall 		return (NULL);
5485e2183daSJulien Grall 	}
5495e2183daSJulien Grall 
5505e2183daSJulien Grall 	prev = xen_intr_port_to_isrc[isrc->xi_port];
5515e2183daSJulien Grall 	xen_intr_port_to_isrc[isrc->xi_port] = isrc;
5525e2183daSJulien Grall 
5535e2183daSJulien Grall #ifdef SMP
5545e2183daSJulien Grall 	isrc->xi_cpu = 0;
5555e2183daSJulien Grall 	error = xen_intr_assign_cpu(isrc, cpu);
5565e2183daSJulien Grall 	if (error)
5575e2183daSJulien Grall 		panic("%s(): unable to rebind Xen channel %u to vCPU%u: %d",
5585e2183daSJulien Grall 		    __func__, isrc->xi_port, cpu, error);
5595e2183daSJulien Grall #endif
5605e2183daSJulien Grall 
5615e2183daSJulien Grall 	evtchn_unmask_port(isrc->xi_port);
5625e2183daSJulien Grall 
5635e2183daSJulien Grall 	return (prev);
5645e2183daSJulien Grall }
5655e2183daSJulien Grall 
5665e2183daSJulien Grall /**
5675e2183daSJulien Grall  * Return this PIC to service after being suspended.
5685e2183daSJulien Grall  */
5695e2183daSJulien Grall void
5705e2183daSJulien Grall xen_intr_resume(void)
5715e2183daSJulien Grall {
5725e2183daSJulien Grall 	shared_info_t *s = HYPERVISOR_shared_info;
5735e2183daSJulien Grall 	u_int isrc_idx;
5745e2183daSJulien Grall 	int i;
5755e2183daSJulien Grall 
5765e2183daSJulien Grall 	/* Reset the per-CPU masks */
5775e2183daSJulien Grall 	CPU_FOREACH(i) {
5785e2183daSJulien Grall 		struct xen_intr_pcpu_data *pcpu;
5795e2183daSJulien Grall 
5805e2183daSJulien Grall 		pcpu = DPCPU_ID_PTR(i, xen_intr_pcpu);
5815e2183daSJulien Grall 		memset(pcpu->evtchn_enabled, i == 0 ? ~0 : 0,
5825e2183daSJulien Grall 		    sizeof(pcpu->evtchn_enabled));
5835e2183daSJulien Grall 	}
5845e2183daSJulien Grall 
5855e2183daSJulien Grall 	/* Mask all event channels. */
5865e2183daSJulien Grall 	for (i = 0; i < nitems(s->evtchn_mask); i++)
5875e2183daSJulien Grall 		atomic_store_rel_long(&s->evtchn_mask[i], ~0);
5885e2183daSJulien Grall 
5895e2183daSJulien Grall 	/* Clear existing port mappings */
5905e2183daSJulien Grall 	for (isrc_idx = 0; isrc_idx < NR_EVENT_CHANNELS; ++isrc_idx)
5915e2183daSJulien Grall 		if (xen_intr_port_to_isrc[isrc_idx] != NULL)
5925e2183daSJulien Grall 			xen_intr_port_to_isrc[isrc_idx]->xi_port =
5935e2183daSJulien Grall 			    INVALID_EVTCHN;
5945e2183daSJulien Grall 
5955e2183daSJulien Grall 	/* Remap in-use isrcs, using xen_intr_port_to_isrc as listing */
5965e2183daSJulien Grall 	for (isrc_idx = 0; isrc_idx < NR_EVENT_CHANNELS; ++isrc_idx) {
5975e2183daSJulien Grall 		struct xenisrc *cur = xen_intr_port_to_isrc[isrc_idx];
5985e2183daSJulien Grall 
5995e2183daSJulien Grall 		/* empty or entry already taken care of */
6005e2183daSJulien Grall 		if (cur == NULL || cur->xi_port == isrc_idx)
6015e2183daSJulien Grall 			continue;
6025e2183daSJulien Grall 
6035e2183daSJulien Grall 		xen_intr_port_to_isrc[isrc_idx] = NULL;
6045e2183daSJulien Grall 
6055e2183daSJulien Grall 		do {
6065e2183daSJulien Grall 			KASSERT(!is_valid_evtchn(cur->xi_port),
6075e2183daSJulien Grall 			    ("%s(): Multiple channels on single intr?",
6085e2183daSJulien Grall 			    __func__));
6095e2183daSJulien Grall 
6105e2183daSJulien Grall 			cur = xen_intr_rebind_isrc(cur);
6115e2183daSJulien Grall 		} while (cur != NULL);
6125e2183daSJulien Grall 	}
6135e2183daSJulien Grall }
6145e2183daSJulien Grall 
6155e2183daSJulien Grall /**
6165e2183daSJulien Grall  * Disable a Xen interrupt source.
6175e2183daSJulien Grall  *
6185e2183daSJulien Grall  * \param isrc  The interrupt source to disable.
6195e2183daSJulien Grall  */
6205e2183daSJulien Grall void
6215e2183daSJulien Grall xen_intr_disable_intr(struct xenisrc *isrc)
6225e2183daSJulien Grall {
6235e2183daSJulien Grall 
6245e2183daSJulien Grall 	evtchn_mask_port(isrc->xi_port);
6255e2183daSJulien Grall }
6265e2183daSJulien Grall 
6275e2183daSJulien Grall /**
6285e2183daSJulien Grall  * Configure CPU affinity for interrupt source event delivery.
6295e2183daSJulien Grall  *
6305e2183daSJulien Grall  * \param isrc     The interrupt source to configure.
6315e2183daSJulien Grall  * \param to_cpu   The id of the CPU for handling future events.
6325e2183daSJulien Grall  *
6335e2183daSJulien Grall  * \returns  0 if successful, otherwise an errno.
6345e2183daSJulien Grall  */
6355e2183daSJulien Grall int
6365e2183daSJulien Grall xen_intr_assign_cpu(struct xenisrc *isrc, u_int to_cpu)
6375e2183daSJulien Grall {
6385e2183daSJulien Grall #ifdef SMP
6395e2183daSJulien Grall 	struct evtchn_bind_vcpu bind_vcpu;
6405e2183daSJulien Grall 	u_int vcpu_id = XEN_CPUID_TO_VCPUID(to_cpu);
6415e2183daSJulien Grall 	int error, masked;
6425e2183daSJulien Grall 
6435e2183daSJulien Grall 	if (!xen_has_percpu_evtchn())
6445e2183daSJulien Grall 		return (EOPNOTSUPP);
6455e2183daSJulien Grall 
6465e2183daSJulien Grall 	mtx_lock(&xen_intr_isrc_lock);
6475e2183daSJulien Grall 	if (!is_valid_evtchn(isrc->xi_port)) {
6485e2183daSJulien Grall 		mtx_unlock(&xen_intr_isrc_lock);
6495e2183daSJulien Grall 		return (EINVAL);
6505e2183daSJulien Grall 	}
6515e2183daSJulien Grall 
6525e2183daSJulien Grall 	/*
6535e2183daSJulien Grall 	 * Mask the event channel while binding it to prevent interrupt
6545e2183daSJulien Grall 	 * delivery with an inconsistent state in isrc->xi_cpu.
6555e2183daSJulien Grall 	 */
6565e2183daSJulien Grall 	masked = evtchn_test_and_set_mask(isrc->xi_port);
6575e2183daSJulien Grall 	if ((isrc->xi_type == EVTCHN_TYPE_VIRQ) ||
6585e2183daSJulien Grall 		(isrc->xi_type == EVTCHN_TYPE_IPI)) {
6595e2183daSJulien Grall 		/*
6605e2183daSJulien Grall 		 * Virtual IRQs are associated with a cpu by
6615e2183daSJulien Grall 		 * the Hypervisor at evtchn_bind_virq time, so
6625e2183daSJulien Grall 		 * all we need to do is update the per-CPU masks.
6635e2183daSJulien Grall 		 */
6645e2183daSJulien Grall 		evtchn_cpu_mask_port(isrc->xi_cpu, isrc->xi_port);
6655e2183daSJulien Grall 		isrc->xi_cpu = to_cpu;
6665e2183daSJulien Grall 		evtchn_cpu_unmask_port(isrc->xi_cpu, isrc->xi_port);
6675e2183daSJulien Grall 		goto out;
6685e2183daSJulien Grall 	}
6695e2183daSJulien Grall 
6705e2183daSJulien Grall 	bind_vcpu.port = isrc->xi_port;
6715e2183daSJulien Grall 	bind_vcpu.vcpu = vcpu_id;
6725e2183daSJulien Grall 
6735e2183daSJulien Grall 	error = HYPERVISOR_event_channel_op(EVTCHNOP_bind_vcpu, &bind_vcpu);
6745e2183daSJulien Grall 	if (isrc->xi_cpu != to_cpu) {
6755e2183daSJulien Grall 		if (error == 0) {
6765e2183daSJulien Grall 			/* Commit to new binding by removing the old one. */
6775e2183daSJulien Grall 			evtchn_cpu_mask_port(isrc->xi_cpu, isrc->xi_port);
6785e2183daSJulien Grall 			isrc->xi_cpu = to_cpu;
6795e2183daSJulien Grall 			evtchn_cpu_unmask_port(isrc->xi_cpu, isrc->xi_port);
6805e2183daSJulien Grall 		}
6815e2183daSJulien Grall 	}
6825e2183daSJulien Grall 
6835e2183daSJulien Grall out:
6845e2183daSJulien Grall 	if (masked == 0)
6855e2183daSJulien Grall 		evtchn_unmask_port(isrc->xi_port);
6865e2183daSJulien Grall 	mtx_unlock(&xen_intr_isrc_lock);
6875e2183daSJulien Grall 	return (0);
6885e2183daSJulien Grall #else
6895e2183daSJulien Grall 	return (EOPNOTSUPP);
6905e2183daSJulien Grall #endif
6915e2183daSJulien Grall }
6925e2183daSJulien Grall 
6935e2183daSJulien Grall /*------------------- Virtual Interrupt Source PIC Functions -----------------*/
6945e2183daSJulien Grall /*
6955e2183daSJulien Grall  * Mask a level triggered interrupt source.
6965e2183daSJulien Grall  *
6975e2183daSJulien Grall  * \param isrc  The interrupt source to mask (if necessary).
6985e2183daSJulien Grall  */
6995e2183daSJulien Grall void
7005e2183daSJulien Grall xen_intr_disable_source(struct xenisrc *isrc)
7015e2183daSJulien Grall {
7025e2183daSJulien Grall 
7035e2183daSJulien Grall 	/*
7045e2183daSJulien Grall 	 * NB: checking if the event channel is already masked is
7055e2183daSJulien Grall 	 * needed because the event channel user-space device
7065e2183daSJulien Grall 	 * masks event channels on its filter as part of its
7075e2183daSJulien Grall 	 * normal operation, and those shouldn't be automatically
7085e2183daSJulien Grall 	 * unmasked by the generic interrupt code. The event channel
7095e2183daSJulien Grall 	 * device will unmask them when needed.
7105e2183daSJulien Grall 	 */
7115e2183daSJulien Grall 	isrc->xi_masked = !!evtchn_test_and_set_mask(isrc->xi_port);
7125e2183daSJulien Grall }
7135e2183daSJulien Grall 
7145e2183daSJulien Grall /*
7155e2183daSJulien Grall  * Unmask a level triggered interrupt source.
7165e2183daSJulien Grall  *
7175e2183daSJulien Grall  * \param isrc  The interrupt source to unmask (if necessary).
7185e2183daSJulien Grall  */
7195e2183daSJulien Grall void
7205e2183daSJulien Grall xen_intr_enable_source(struct xenisrc *isrc)
7215e2183daSJulien Grall {
7225e2183daSJulien Grall 
7235e2183daSJulien Grall 	if (isrc->xi_masked == 0)
7245e2183daSJulien Grall 		evtchn_unmask_port(isrc->xi_port);
7255e2183daSJulien Grall }
7265e2183daSJulien Grall 
7275e2183daSJulien Grall /*
7285e2183daSJulien Grall  * Enable and unmask the interrupt source.
7295e2183daSJulien Grall  *
7305e2183daSJulien Grall  * \param isrc  The interrupt source to enable.
7315e2183daSJulien Grall  */
7325e2183daSJulien Grall void
7335e2183daSJulien Grall xen_intr_enable_intr(struct xenisrc *isrc)
7345e2183daSJulien Grall {
7355e2183daSJulien Grall 
7365e2183daSJulien Grall 	evtchn_unmask_port(isrc->xi_port);
7375e2183daSJulien Grall }
7385e2183daSJulien Grall 
7395e2183daSJulien Grall /*--------------------------- Public Functions -------------------------------*/
7405e2183daSJulien Grall /*------- API comments for these methods can be found in xen/xenintr.h -------*/
7415e2183daSJulien Grall int
7425e2183daSJulien Grall xen_intr_bind_local_port(device_t dev, evtchn_port_t local_port,
7435e2183daSJulien Grall     driver_filter_t filter, driver_intr_t handler, void *arg,
7445e2183daSJulien Grall     enum intr_type flags, xen_intr_handle_t *port_handlep)
7455e2183daSJulien Grall {
7465e2183daSJulien Grall 	struct xenisrc *isrc;
7475e2183daSJulien Grall 	int error;
7485e2183daSJulien Grall 
7495e2183daSJulien Grall 	error = xen_intr_bind_isrc(&isrc, local_port, EVTCHN_TYPE_PORT,
7505e2183daSJulien Grall 	    device_get_nameunit(dev), filter, handler, arg, flags,
7515e2183daSJulien Grall 	    port_handlep);
7525e2183daSJulien Grall 	if (error != 0)
7535e2183daSJulien Grall 		return (error);
7545e2183daSJulien Grall 
7555e2183daSJulien Grall 	/*
7565e2183daSJulien Grall 	 * The Event Channel API didn't open this port, so it is not
7575e2183daSJulien Grall 	 * responsible for closing it automatically on unbind.
7585e2183daSJulien Grall 	 */
7595e2183daSJulien Grall 	isrc->xi_close = 0;
7605e2183daSJulien Grall 	return (0);
7615e2183daSJulien Grall }
7625e2183daSJulien Grall 
7635e2183daSJulien Grall int
7645e2183daSJulien Grall xen_intr_alloc_and_bind_local_port(device_t dev, u_int remote_domain,
7655e2183daSJulien Grall     driver_filter_t filter, driver_intr_t handler, void *arg,
7665e2183daSJulien Grall     enum intr_type flags, xen_intr_handle_t *port_handlep)
7675e2183daSJulien Grall {
7685e2183daSJulien Grall 	struct xenisrc *isrc;
7695e2183daSJulien Grall 	struct evtchn_alloc_unbound alloc_unbound;
7705e2183daSJulien Grall 	int error;
7715e2183daSJulien Grall 
7725e2183daSJulien Grall 	alloc_unbound.dom        = DOMID_SELF;
7735e2183daSJulien Grall 	alloc_unbound.remote_dom = remote_domain;
7745e2183daSJulien Grall 	error = HYPERVISOR_event_channel_op(EVTCHNOP_alloc_unbound,
7755e2183daSJulien Grall 		    &alloc_unbound);
7765e2183daSJulien Grall 	if (error != 0) {
7775e2183daSJulien Grall 		/*
7785e2183daSJulien Grall 		 * XXX Trap Hypercall error code Linuxisms in
7795e2183daSJulien Grall 		 *     the HYPERCALL layer.
7805e2183daSJulien Grall 		 */
7815e2183daSJulien Grall 		return (-error);
7825e2183daSJulien Grall 	}
7835e2183daSJulien Grall 
7845e2183daSJulien Grall 	error = xen_intr_bind_isrc(&isrc, alloc_unbound.port, EVTCHN_TYPE_PORT,
7855e2183daSJulien Grall 	    device_get_nameunit(dev), filter, handler, arg, flags,
7865e2183daSJulien Grall 	    port_handlep);
7875e2183daSJulien Grall 	if (error != 0) {
7885e2183daSJulien Grall 		evtchn_close_t close = { .port = alloc_unbound.port };
7895e2183daSJulien Grall 		if (HYPERVISOR_event_channel_op(EVTCHNOP_close, &close))
7905e2183daSJulien Grall 			panic("EVTCHNOP_close failed");
7915e2183daSJulien Grall 		return (error);
7925e2183daSJulien Grall 	}
7935e2183daSJulien Grall 
7945e2183daSJulien Grall 	isrc->xi_close = 1;
7955e2183daSJulien Grall 	return (0);
7965e2183daSJulien Grall }
7975e2183daSJulien Grall 
7985e2183daSJulien Grall int
7995e2183daSJulien Grall xen_intr_bind_remote_port(device_t dev, u_int remote_domain,
8005e2183daSJulien Grall     u_int remote_port, driver_filter_t filter, driver_intr_t handler,
8015e2183daSJulien Grall     void *arg, enum intr_type flags, xen_intr_handle_t *port_handlep)
8025e2183daSJulien Grall {
8035e2183daSJulien Grall 	struct xenisrc *isrc;
8045e2183daSJulien Grall 	struct evtchn_bind_interdomain bind_interdomain;
8055e2183daSJulien Grall 	int error;
8065e2183daSJulien Grall 
8075e2183daSJulien Grall 	bind_interdomain.remote_dom  = remote_domain;
8085e2183daSJulien Grall 	bind_interdomain.remote_port = remote_port;
8095e2183daSJulien Grall 	error = HYPERVISOR_event_channel_op(EVTCHNOP_bind_interdomain,
8105e2183daSJulien Grall 					    &bind_interdomain);
8115e2183daSJulien Grall 	if (error != 0) {
8125e2183daSJulien Grall 		/*
8135e2183daSJulien Grall 		 * XXX Trap Hypercall error code Linuxisms in
8145e2183daSJulien Grall 		 *     the HYPERCALL layer.
8155e2183daSJulien Grall 		 */
8165e2183daSJulien Grall 		return (-error);
8175e2183daSJulien Grall 	}
8185e2183daSJulien Grall 
8195e2183daSJulien Grall 	error = xen_intr_bind_isrc(&isrc, bind_interdomain.local_port,
8205e2183daSJulien Grall 	    EVTCHN_TYPE_PORT, device_get_nameunit(dev), filter, handler, arg,
8215e2183daSJulien Grall 	    flags, port_handlep);
8225e2183daSJulien Grall 	if (error) {
8235e2183daSJulien Grall 		evtchn_close_t close = { .port = bind_interdomain.local_port };
8245e2183daSJulien Grall 		if (HYPERVISOR_event_channel_op(EVTCHNOP_close, &close))
8255e2183daSJulien Grall 			panic("EVTCHNOP_close failed");
8265e2183daSJulien Grall 		return (error);
8275e2183daSJulien Grall 	}
8285e2183daSJulien Grall 
8295e2183daSJulien Grall 	/*
8305e2183daSJulien Grall 	 * The Event Channel API opened this port, so it is
8315e2183daSJulien Grall 	 * responsible for closing it automatically on unbind.
8325e2183daSJulien Grall 	 */
8335e2183daSJulien Grall 	isrc->xi_close = 1;
8345e2183daSJulien Grall 	return (0);
8355e2183daSJulien Grall }
8365e2183daSJulien Grall 
8375e2183daSJulien Grall int
8385e2183daSJulien Grall xen_intr_bind_virq(device_t dev, u_int virq, u_int cpu,
8395e2183daSJulien Grall     driver_filter_t filter, driver_intr_t handler, void *arg,
8405e2183daSJulien Grall     enum intr_type flags, xen_intr_handle_t *port_handlep)
8415e2183daSJulien Grall {
8425e2183daSJulien Grall 	u_int vcpu_id = XEN_CPUID_TO_VCPUID(cpu);
8435e2183daSJulien Grall 	struct xenisrc *isrc;
8445e2183daSJulien Grall 	struct evtchn_bind_virq bind_virq = { .virq = virq, .vcpu = vcpu_id };
8455e2183daSJulien Grall 	int error;
8465e2183daSJulien Grall 
8475e2183daSJulien Grall 	isrc = NULL;
8485e2183daSJulien Grall 	error = HYPERVISOR_event_channel_op(EVTCHNOP_bind_virq, &bind_virq);
8495e2183daSJulien Grall 	if (error != 0) {
8505e2183daSJulien Grall 		/*
8515e2183daSJulien Grall 		 * XXX Trap Hypercall error code Linuxisms in
8525e2183daSJulien Grall 		 *     the HYPERCALL layer.
8535e2183daSJulien Grall 		 */
8545e2183daSJulien Grall 		return (-error);
8555e2183daSJulien Grall 	}
8565e2183daSJulien Grall 
8575e2183daSJulien Grall 	error = xen_intr_bind_isrc(&isrc, bind_virq.port, EVTCHN_TYPE_VIRQ,
8585e2183daSJulien Grall 	    device_get_nameunit(dev), filter, handler, arg, flags,
8595e2183daSJulien Grall 	    port_handlep);
8605e2183daSJulien Grall 
8615e2183daSJulien Grall #ifdef SMP
8625e2183daSJulien Grall 	if (error == 0)
8635e2183daSJulien Grall 		error = xen_arch_intr_event_bind(isrc, cpu);
8645e2183daSJulien Grall #endif
8655e2183daSJulien Grall 
8665e2183daSJulien Grall 	if (error != 0) {
8675e2183daSJulien Grall 		evtchn_close_t close = { .port = bind_virq.port };
8685e2183daSJulien Grall 
869*c880f12fSElliott Mitchell 		xen_intr_unbind(port_handlep);
8705e2183daSJulien Grall 		if (HYPERVISOR_event_channel_op(EVTCHNOP_close, &close))
8715e2183daSJulien Grall 			panic("EVTCHNOP_close failed");
8725e2183daSJulien Grall 		return (error);
8735e2183daSJulien Grall 	}
8745e2183daSJulien Grall 
8755e2183daSJulien Grall #ifdef SMP
8765e2183daSJulien Grall 	if (isrc->xi_cpu != cpu) {
8775e2183daSJulien Grall 		/*
8785e2183daSJulien Grall 		 * Too early in the boot process for the generic interrupt
8795e2183daSJulien Grall 		 * code to perform the binding.  Update our event channel
8805e2183daSJulien Grall 		 * masks manually so events can't fire on the wrong cpu
8815e2183daSJulien Grall 		 * during AP startup.
8825e2183daSJulien Grall 		 */
8835e2183daSJulien Grall 		xen_intr_assign_cpu(isrc, cpu);
8845e2183daSJulien Grall 	}
8855e2183daSJulien Grall #endif
8865e2183daSJulien Grall 
8875e2183daSJulien Grall 	/*
8885e2183daSJulien Grall 	 * The Event Channel API opened this port, so it is
8895e2183daSJulien Grall 	 * responsible for closing it automatically on unbind.
8905e2183daSJulien Grall 	 */
8915e2183daSJulien Grall 	isrc->xi_close = 1;
8925e2183daSJulien Grall 	isrc->xi_virq = virq;
8935e2183daSJulien Grall 
8945e2183daSJulien Grall 	return (0);
8955e2183daSJulien Grall }
8965e2183daSJulien Grall 
8975e2183daSJulien Grall int
8985e2183daSJulien Grall xen_intr_alloc_and_bind_ipi(u_int cpu, driver_filter_t filter,
8995e2183daSJulien Grall     enum intr_type flags, xen_intr_handle_t *port_handlep)
9005e2183daSJulien Grall {
9015e2183daSJulien Grall #ifdef SMP
9025e2183daSJulien Grall 	u_int vcpu_id = XEN_CPUID_TO_VCPUID(cpu);
9035e2183daSJulien Grall 	struct xenisrc *isrc;
9045e2183daSJulien Grall 	struct evtchn_bind_ipi bind_ipi = { .vcpu = vcpu_id };
9055e2183daSJulien Grall 	/* Same size as the one used by intr_handler->ih_name. */
9065e2183daSJulien Grall 	char name[MAXCOMLEN + 1];
9075e2183daSJulien Grall 	int error;
9085e2183daSJulien Grall 
9095e2183daSJulien Grall 	isrc = NULL;
9105e2183daSJulien Grall 	error = HYPERVISOR_event_channel_op(EVTCHNOP_bind_ipi, &bind_ipi);
9115e2183daSJulien Grall 	if (error != 0) {
9125e2183daSJulien Grall 		/*
9135e2183daSJulien Grall 		 * XXX Trap Hypercall error code Linuxisms in
9145e2183daSJulien Grall 		 *     the HYPERCALL layer.
9155e2183daSJulien Grall 		 */
9165e2183daSJulien Grall 		return (-error);
9175e2183daSJulien Grall 	}
9185e2183daSJulien Grall 
9195e2183daSJulien Grall 	snprintf(name, sizeof(name), "cpu%u", cpu);
9205e2183daSJulien Grall 
9215e2183daSJulien Grall 	error = xen_intr_bind_isrc(&isrc, bind_ipi.port, EVTCHN_TYPE_IPI,
9225e2183daSJulien Grall 	    name, filter, NULL, NULL, flags, port_handlep);
9235e2183daSJulien Grall 	if (error != 0) {
9245e2183daSJulien Grall 		evtchn_close_t close = { .port = bind_ipi.port };
9255e2183daSJulien Grall 
926*c880f12fSElliott Mitchell 		xen_intr_unbind(port_handlep);
9275e2183daSJulien Grall 		if (HYPERVISOR_event_channel_op(EVTCHNOP_close, &close))
9285e2183daSJulien Grall 			panic("EVTCHNOP_close failed");
9295e2183daSJulien Grall 		return (error);
9305e2183daSJulien Grall 	}
9315e2183daSJulien Grall 
9325e2183daSJulien Grall 	if (isrc->xi_cpu != cpu) {
9335e2183daSJulien Grall 		/*
9345e2183daSJulien Grall 		 * Too early in the boot process for the generic interrupt
9355e2183daSJulien Grall 		 * code to perform the binding.  Update our event channel
9365e2183daSJulien Grall 		 * masks manually so events can't fire on the wrong cpu
9375e2183daSJulien Grall 		 * during AP startup.
9385e2183daSJulien Grall 		 */
9395e2183daSJulien Grall 		xen_intr_assign_cpu(isrc, cpu);
9405e2183daSJulien Grall 	}
9415e2183daSJulien Grall 
9425e2183daSJulien Grall 	/*
9435e2183daSJulien Grall 	 * The Event Channel API opened this port, so it is
9445e2183daSJulien Grall 	 * responsible for closing it automatically on unbind.
9455e2183daSJulien Grall 	 */
9465e2183daSJulien Grall 	isrc->xi_close = 1;
9475e2183daSJulien Grall 	return (0);
9485e2183daSJulien Grall #else
9495e2183daSJulien Grall 	return (EOPNOTSUPP);
9505e2183daSJulien Grall #endif
9515e2183daSJulien Grall }
9525e2183daSJulien Grall 
9535e2183daSJulien Grall int
9545e2183daSJulien Grall xen_intr_describe(xen_intr_handle_t port_handle, const char *fmt, ...)
9555e2183daSJulien Grall {
9565e2183daSJulien Grall 	char descr[MAXCOMLEN + 1];
9575e2183daSJulien Grall 	struct xenisrc *isrc;
9585e2183daSJulien Grall 	va_list ap;
9595e2183daSJulien Grall 
9605e2183daSJulien Grall 	isrc = xen_intr_isrc_from_handle(port_handle);
9615e2183daSJulien Grall 	if (isrc == NULL)
9625e2183daSJulien Grall 		return (EINVAL);
9635e2183daSJulien Grall 
9645e2183daSJulien Grall 	va_start(ap, fmt);
9655e2183daSJulien Grall 	vsnprintf(descr, sizeof(descr), fmt, ap);
9665e2183daSJulien Grall 	va_end(ap);
9675e2183daSJulien Grall 	return (xen_arch_intr_describe(isrc, isrc->xi_cookie, descr));
9685e2183daSJulien Grall }
9695e2183daSJulien Grall 
9705e2183daSJulien Grall void
9715e2183daSJulien Grall xen_intr_unbind(xen_intr_handle_t *port_handlep)
9725e2183daSJulien Grall {
9735e2183daSJulien Grall 	struct xenisrc *isrc;
9745e2183daSJulien Grall 
9755e2183daSJulien Grall 	KASSERT(port_handlep != NULL,
9765e2183daSJulien Grall 	    ("NULL xen_intr_handle_t passed to %s", __func__));
9775e2183daSJulien Grall 
9785e2183daSJulien Grall 	isrc = xen_intr_isrc_from_handle(*port_handlep);
9795e2183daSJulien Grall 	*port_handlep = NULL;
9805e2183daSJulien Grall 	if (isrc == NULL)
9815e2183daSJulien Grall 		return;
9825e2183daSJulien Grall 
9835e2183daSJulien Grall 	mtx_lock(&xen_intr_isrc_lock);
9845e2183daSJulien Grall 	if (refcount_release(&isrc->xi_refcount) == 0) {
9855e2183daSJulien Grall 		mtx_unlock(&xen_intr_isrc_lock);
9865e2183daSJulien Grall 		return;
9875e2183daSJulien Grall 	}
9885e2183daSJulien Grall 	mtx_unlock(&xen_intr_isrc_lock);
9895e2183daSJulien Grall 
9905e2183daSJulien Grall 	if (isrc->xi_cookie != NULL)
9915e2183daSJulien Grall 		xen_arch_intr_remove_handler(isrc, isrc->xi_cookie);
9925e2183daSJulien Grall 	xen_intr_release_isrc(isrc);
9935e2183daSJulien Grall }
9945e2183daSJulien Grall 
9955e2183daSJulien Grall void
9965e2183daSJulien Grall xen_intr_signal(xen_intr_handle_t handle)
9975e2183daSJulien Grall {
9985e2183daSJulien Grall 	struct xenisrc *isrc;
9995e2183daSJulien Grall 
10005e2183daSJulien Grall 	isrc = xen_intr_isrc_from_handle(handle);
10015e2183daSJulien Grall 	if (isrc != NULL) {
10025e2183daSJulien Grall 		KASSERT(isrc->xi_type == EVTCHN_TYPE_PORT ||
10035e2183daSJulien Grall 			isrc->xi_type == EVTCHN_TYPE_IPI,
10045e2183daSJulien Grall 			("evtchn_signal on something other than a local port"));
10055e2183daSJulien Grall 		struct evtchn_send send = { .port = isrc->xi_port };
10065e2183daSJulien Grall 		(void)HYPERVISOR_event_channel_op(EVTCHNOP_send, &send);
10075e2183daSJulien Grall 	}
10085e2183daSJulien Grall }
10095e2183daSJulien Grall 
10105e2183daSJulien Grall evtchn_port_t
10115e2183daSJulien Grall xen_intr_port(xen_intr_handle_t handle)
10125e2183daSJulien Grall {
10135e2183daSJulien Grall 	struct xenisrc *isrc;
10145e2183daSJulien Grall 
10155e2183daSJulien Grall 	isrc = xen_intr_isrc_from_handle(handle);
10165e2183daSJulien Grall 	if (isrc == NULL)
10175e2183daSJulien Grall 		return (0);
10185e2183daSJulien Grall 
10195e2183daSJulien Grall 	return (isrc->xi_port);
10205e2183daSJulien Grall }
10215e2183daSJulien Grall 
10225e2183daSJulien Grall int
10235e2183daSJulien Grall xen_intr_add_handler(const char *name, driver_filter_t filter,
10245e2183daSJulien Grall     driver_intr_t handler, void *arg, enum intr_type flags,
10255e2183daSJulien Grall     xen_intr_handle_t handle)
10265e2183daSJulien Grall {
10275e2183daSJulien Grall 	struct xenisrc *isrc;
10285e2183daSJulien Grall 	int error;
10295e2183daSJulien Grall 
10305e2183daSJulien Grall 	isrc = xen_intr_isrc_from_handle(handle);
10315e2183daSJulien Grall 	if (isrc == NULL || isrc->xi_cookie != NULL)
10325e2183daSJulien Grall 		return (EINVAL);
10335e2183daSJulien Grall 
10345e2183daSJulien Grall 	error = xen_arch_intr_add_handler(name, filter, handler, arg,
10355e2183daSJulien Grall 	    flags | INTR_EXCL, isrc, &isrc->xi_cookie);
10365e2183daSJulien Grall 	if (error != 0)
10375e2183daSJulien Grall 		printf("%s: %s: add handler failed: %d\n", name, __func__,
10385e2183daSJulien Grall 		    error);
10395e2183daSJulien Grall 
10405e2183daSJulien Grall 	return (error);
10415e2183daSJulien Grall }
10425e2183daSJulien Grall 
10435e2183daSJulien Grall int
10445e2183daSJulien Grall xen_intr_get_evtchn_from_port(evtchn_port_t port, xen_intr_handle_t *handlep)
10455e2183daSJulien Grall {
10465e2183daSJulien Grall 
10475e2183daSJulien Grall 	if (!is_valid_evtchn(port))
10485e2183daSJulien Grall 		return (EINVAL);
10495e2183daSJulien Grall 
10505e2183daSJulien Grall 	if (handlep == NULL) {
10515e2183daSJulien Grall 		return (EINVAL);
10525e2183daSJulien Grall 	}
10535e2183daSJulien Grall 
10545e2183daSJulien Grall 	mtx_lock(&xen_intr_isrc_lock);
10555e2183daSJulien Grall 	if (xen_intr_port_to_isrc[port] == NULL) {
10565e2183daSJulien Grall 		mtx_unlock(&xen_intr_isrc_lock);
10575e2183daSJulien Grall 		return (EINVAL);
10585e2183daSJulien Grall 	}
10595e2183daSJulien Grall 	refcount_acquire(&xen_intr_port_to_isrc[port]->xi_refcount);
10605e2183daSJulien Grall 	mtx_unlock(&xen_intr_isrc_lock);
10615e2183daSJulien Grall 
10625e2183daSJulien Grall 	/* Assign the opaque handler */
10635e2183daSJulien Grall 	*handlep = xen_intr_handle_from_isrc(xen_intr_port_to_isrc[port]);
10645e2183daSJulien Grall 
10655e2183daSJulien Grall 	return (0);
10665e2183daSJulien Grall }
10675e2183daSJulien Grall 
10685e2183daSJulien Grall #ifdef DDB
10695e2183daSJulien Grall static const char *
10705e2183daSJulien Grall xen_intr_print_type(enum evtchn_type type)
10715e2183daSJulien Grall {
10725e2183daSJulien Grall 	static const char *evtchn_type_to_string[EVTCHN_TYPE_COUNT] = {
10735e2183daSJulien Grall 		[EVTCHN_TYPE_UNBOUND]	= "UNBOUND",
10745e2183daSJulien Grall 		[EVTCHN_TYPE_VIRQ]	= "VIRQ",
10755e2183daSJulien Grall 		[EVTCHN_TYPE_IPI]	= "IPI",
10765e2183daSJulien Grall 		[EVTCHN_TYPE_PORT]	= "PORT",
10775e2183daSJulien Grall 	};
10785e2183daSJulien Grall 
10795e2183daSJulien Grall 	if (type >= EVTCHN_TYPE_COUNT)
10805e2183daSJulien Grall 		return ("UNKNOWN");
10815e2183daSJulien Grall 
10825e2183daSJulien Grall 	return (evtchn_type_to_string[type]);
10835e2183daSJulien Grall }
10845e2183daSJulien Grall 
10855e2183daSJulien Grall static void
10865e2183daSJulien Grall xen_intr_dump_port(struct xenisrc *isrc)
10875e2183daSJulien Grall {
10885e2183daSJulien Grall 	struct xen_intr_pcpu_data *pcpu;
10895e2183daSJulien Grall 	shared_info_t *s = HYPERVISOR_shared_info;
10905e2183daSJulien Grall 	u_int i;
10915e2183daSJulien Grall 
10925e2183daSJulien Grall 	db_printf("Port %d Type: %s\n",
10935e2183daSJulien Grall 	    isrc->xi_port, xen_intr_print_type(isrc->xi_type));
10945e2183daSJulien Grall 	if (isrc->xi_type == EVTCHN_TYPE_VIRQ)
10955e2183daSJulien Grall 		db_printf("\tVirq: %u\n", isrc->xi_virq);
10965e2183daSJulien Grall 
10975e2183daSJulien Grall 	db_printf("\tMasked: %d Pending: %d\n",
10985e2183daSJulien Grall 	    !!xen_test_bit(isrc->xi_port, &s->evtchn_mask[0]),
10995e2183daSJulien Grall 	    !!xen_test_bit(isrc->xi_port, &s->evtchn_pending[0]));
11005e2183daSJulien Grall 
11015e2183daSJulien Grall 	db_printf("\tPer-CPU Masks: ");
11025e2183daSJulien Grall 	CPU_FOREACH(i) {
11035e2183daSJulien Grall 		pcpu = DPCPU_ID_PTR(i, xen_intr_pcpu);
11045e2183daSJulien Grall 		db_printf("cpu#%u: %d ", i,
11055e2183daSJulien Grall 		    !!xen_test_bit(isrc->xi_port, pcpu->evtchn_enabled));
11065e2183daSJulien Grall 	}
11075e2183daSJulien Grall 	db_printf("\n");
11085e2183daSJulien Grall }
11095e2183daSJulien Grall 
11105e2183daSJulien Grall DB_SHOW_COMMAND(xen_evtchn, db_show_xen_evtchn)
11115e2183daSJulien Grall {
11125e2183daSJulien Grall 	u_int i;
11135e2183daSJulien Grall 
11145e2183daSJulien Grall 	if (!xen_domain()) {
11155e2183daSJulien Grall 		db_printf("Only available on Xen guests\n");
11165e2183daSJulien Grall 		return;
11175e2183daSJulien Grall 	}
11185e2183daSJulien Grall 
11195e2183daSJulien Grall 	for (i = 0; i < NR_EVENT_CHANNELS; i++) {
11205e2183daSJulien Grall 		struct xenisrc *isrc;
11215e2183daSJulien Grall 
11225e2183daSJulien Grall 		isrc = xen_intr_port_to_isrc[i];
11235e2183daSJulien Grall 		if (isrc == NULL)
11245e2183daSJulien Grall 			continue;
11255e2183daSJulien Grall 
11265e2183daSJulien Grall 		xen_intr_dump_port(isrc);
11275e2183daSJulien Grall 	}
11285e2183daSJulien Grall }
11295e2183daSJulien Grall #endif /* DDB */
1130