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