xref: /freebsd/sys/dev/xen/bus/xen_intr.c (revision f750dce9)
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 	 */
87ed917e0fSElliott 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
xen_intr_handle_from_isrc(struct xenisrc * isrc)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 *
xen_intr_isrc_from_handle(xen_intr_handle_t handle)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
evtchn_cpu_mask_port(u_int cpu,evtchn_port_t port)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);
1694ece7996SRoger Pau Monné 	KASSERT(is_valid_evtchn(port), ("Invalid event channel port"));
1705e2183daSJulien Grall 	xen_clear_bit(port, pcpu->evtchn_enabled);
1715e2183daSJulien Grall }
1725e2183daSJulien Grall 
1735e2183daSJulien Grall /**
1745e2183daSJulien Grall  * Enable signal delivery for an event channel port on the
1755e2183daSJulien Grall  * specified CPU.
1765e2183daSJulien Grall  *
1775e2183daSJulien Grall  * \param port  The event channel port to unmask.
1785e2183daSJulien Grall  *
1795e2183daSJulien Grall  * This API is used to manage the port<=>CPU binding of event
1805e2183daSJulien Grall  * channel handlers.
1815e2183daSJulien Grall  *
1825e2183daSJulien Grall  * \note  This operation does not guarantee that event delivery
1835e2183daSJulien Grall  *        is enabled for this event channel port.  The port must
1845e2183daSJulien Grall  *        also be globally enabled.  See evtchn_unmask().
1855e2183daSJulien Grall  */
1865e2183daSJulien Grall static inline void
evtchn_cpu_unmask_port(u_int cpu,evtchn_port_t port)1875e2183daSJulien Grall evtchn_cpu_unmask_port(u_int cpu, evtchn_port_t port)
1885e2183daSJulien Grall {
1895e2183daSJulien Grall 	struct xen_intr_pcpu_data *pcpu;
1905e2183daSJulien Grall 
1915e2183daSJulien Grall 	pcpu = DPCPU_ID_PTR(cpu, xen_intr_pcpu);
1924ece7996SRoger Pau Monné 	KASSERT(is_valid_evtchn(port), ("Invalid event channel port"));
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
xen_intr_release_isrc(struct xenisrc * isrc)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
xen_intr_bind_isrc(struct xenisrc ** isrcp,evtchn_port_t local_port,enum evtchn_type type,const char * intr_owner,driver_filter_t filter,driver_intr_t handler,void * arg,enum intr_type flags,xen_intr_handle_t * const port_handlep)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
xen_intr_active_ports(const struct xen_intr_pcpu_data * const pcpu,const u_int idx)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  *
344*f750dce9SRoger Pau Monné  * \param unused
3455e2183daSJulien Grall  */
3465e2183daSJulien Grall int
xen_intr_handle_upcall(void * unused __unused)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 
357*f750dce9SRoger Pau Monné 	/*
358*f750dce9SRoger Pau Monné 	 * The upcall handler is an interrupt handler itself (that calls other
359*f750dce9SRoger Pau Monné 	 * interrupt handlers), hence the caller has the responsibility to
360*f750dce9SRoger Pau Monné 	 * increase td_intr_nesting_level ahead of dispatching the upcall
361*f750dce9SRoger Pau Monné 	 * handler.
362*f750dce9SRoger Pau Monné 	 */
363*f750dce9SRoger Pau Monné 	KASSERT(curthread->td_intr_nesting_level > 0,
364*f750dce9SRoger Pau Monné 	        ("Unexpected thread context"));
365*f750dce9SRoger Pau Monné 
3665e2183daSJulien Grall 	/* We must remain on the same vCPU during this function */
3675e2183daSJulien Grall 	CRITICAL_ASSERT(curthread);
3685e2183daSJulien Grall 
3695e2183daSJulien Grall 	cpu = PCPU_GET(cpuid);
3705e2183daSJulien Grall 	pc  = DPCPU_PTR(xen_intr_pcpu);
3715e2183daSJulien Grall 	v   = DPCPU_GET(vcpu_info);
3725e2183daSJulien Grall 
3735e2183daSJulien Grall 	if (!xen_has_percpu_evtchn()) {
3745e2183daSJulien Grall 		KASSERT((cpu == 0), ("Fired PCI event callback on wrong CPU"));
3755e2183daSJulien Grall 	}
3765e2183daSJulien Grall 
3775e2183daSJulien Grall 	v->evtchn_upcall_pending = 0;
3785e2183daSJulien Grall /* No need for a barrier on x86 -- XCHG is a barrier on x86. */
3795e2183daSJulien Grall #if !defined(__amd64__) && !defined(__i386__)
3805e2183daSJulien Grall 	/* Clear master flag /before/ clearing selector flag. */
3815e2183daSJulien Grall 	wmb();
3825e2183daSJulien Grall #endif
3834c9e6ad3SElliott Mitchell 	l1 = atomic_readandclear_xen_ulong(&v->evtchn_pending_sel);
3845e2183daSJulien Grall 
3855e2183daSJulien Grall 	l1i = pc->last_processed_l1i;
3865e2183daSJulien Grall 	l2i = pc->last_processed_l2i;
3875e2183daSJulien Grall 
3885e2183daSJulien Grall 	while (l1 != 0) {
3895e2183daSJulien Grall 		l1i = (l1i + 1) % LONG_BIT;
3905e2183daSJulien Grall 		masked_l1 = l1 & ((~0UL) << l1i);
3915e2183daSJulien Grall 
3925e2183daSJulien Grall 		if (masked_l1 == 0) {
3935e2183daSJulien Grall 			/*
3945e2183daSJulien Grall 			 * if we masked out all events, wrap around
3955e2183daSJulien Grall 			 * to the beginning.
3965e2183daSJulien Grall 			 */
3975e2183daSJulien Grall 			l1i = LONG_BIT - 1;
3985e2183daSJulien Grall 			l2i = LONG_BIT - 1;
3995e2183daSJulien Grall 			continue;
4005e2183daSJulien Grall 		}
4015e2183daSJulien Grall 		l1i = ffsl(masked_l1) - 1;
4025e2183daSJulien Grall 
4035e2183daSJulien Grall 		do {
4045e2183daSJulien Grall 			l2 = xen_intr_active_ports(pc, l1i);
4055e2183daSJulien Grall 
4065e2183daSJulien Grall 			l2i = (l2i + 1) % LONG_BIT;
4075e2183daSJulien Grall 			masked_l2 = l2 & ((~0UL) << l2i);
4085e2183daSJulien Grall 
4095e2183daSJulien Grall 			if (masked_l2 == 0) {
4105e2183daSJulien Grall 				/* if we masked out all events, move on */
4115e2183daSJulien Grall 				l2i = LONG_BIT - 1;
4125e2183daSJulien Grall 				break;
4135e2183daSJulien Grall 			}
4145e2183daSJulien Grall 			l2i = ffsl(masked_l2) - 1;
4155e2183daSJulien Grall 
4165e2183daSJulien Grall 			/* process port */
4175e2183daSJulien Grall 			port = (l1i * LONG_BIT) + l2i;
4185e2183daSJulien Grall 			evtchn_clear_port(port);
4195e2183daSJulien Grall 
4205e2183daSJulien Grall 			isrc = xen_intr_port_to_isrc[port];
4215e2183daSJulien Grall 			if (__predict_false(isrc == NULL))
4225e2183daSJulien Grall 				continue;
4235e2183daSJulien Grall 
4245e2183daSJulien Grall 			/* Make sure we are firing on the right vCPU */
4255e2183daSJulien Grall 			KASSERT((isrc->xi_cpu == PCPU_GET(cpuid)),
4265e2183daSJulien Grall 				("Received unexpected event on vCPU#%u, event bound to vCPU#%u",
4275e2183daSJulien Grall 				PCPU_GET(cpuid), isrc->xi_cpu));
4285e2183daSJulien Grall 
429*f750dce9SRoger Pau Monné 			/*
430*f750dce9SRoger Pau Monné 			 * Reduce interrupt nesting level ahead of calling the
431*f750dce9SRoger Pau Monné 			 * per-arch interrupt dispatch helper.  This is
432*f750dce9SRoger Pau Monné 			 * required because the per-arch dispatcher will also
433*f750dce9SRoger Pau Monné 			 * increase td_intr_nesting_level, and then handlers
434*f750dce9SRoger Pau Monné 			 * would wrongly see td_intr_nesting_level = 2 when
435*f750dce9SRoger Pau Monné 			 * there's no nesting at all.
436*f750dce9SRoger Pau Monné 			 */
437*f750dce9SRoger Pau Monné 			curthread->td_intr_nesting_level--;
4385e2183daSJulien Grall 			xen_arch_intr_execute_handlers(isrc, trap_frame);
439*f750dce9SRoger Pau Monné 			curthread->td_intr_nesting_level++;
4405e2183daSJulien Grall 
4415e2183daSJulien Grall 			/*
4425e2183daSJulien Grall 			 * If this is the final port processed,
4435e2183daSJulien Grall 			 * we'll pick up here+1 next time.
4445e2183daSJulien Grall 			 */
4455e2183daSJulien Grall 			pc->last_processed_l1i = l1i;
4465e2183daSJulien Grall 			pc->last_processed_l2i = l2i;
4475e2183daSJulien Grall 
4485e2183daSJulien Grall 		} while (l2i != LONG_BIT - 1);
4495e2183daSJulien Grall 
4505e2183daSJulien Grall 		l2 = xen_intr_active_ports(pc, l1i);
4515e2183daSJulien Grall 		if (l2 == 0) {
4525e2183daSJulien Grall 			/*
4535e2183daSJulien Grall 			 * We handled all ports, so we can clear the
4545e2183daSJulien Grall 			 * selector bit.
4555e2183daSJulien Grall 			 */
4565e2183daSJulien Grall 			l1 &= ~(1UL << l1i);
4575e2183daSJulien Grall 		}
4585e2183daSJulien Grall 	}
4595e2183daSJulien Grall 
4605e2183daSJulien Grall 	return (FILTER_HANDLED);
4615e2183daSJulien Grall }
4625e2183daSJulien Grall 
4635e2183daSJulien Grall static int
xen_intr_init(void * dummy __unused)4645e2183daSJulien Grall xen_intr_init(void *dummy __unused)
4655e2183daSJulien Grall {
4665e2183daSJulien Grall 	shared_info_t *s = HYPERVISOR_shared_info;
4675e2183daSJulien Grall 	struct xen_intr_pcpu_data *pcpu;
4685e2183daSJulien Grall 	int i;
4695e2183daSJulien Grall 
4705e2183daSJulien Grall 	if (!xen_domain())
4715e2183daSJulien Grall 		return (0);
4725e2183daSJulien Grall 
4735e2183daSJulien Grall 	_Static_assert(is_valid_evtchn(0),
4745e2183daSJulien Grall 	    "is_valid_evtchn(0) fails (unused by Xen, but valid by interface");
4755e2183daSJulien Grall 	_Static_assert(is_valid_evtchn(NR_EVENT_CHANNELS - 1),
4765e2183daSJulien Grall 	    "is_valid_evtchn(max) fails (is a valid channel)");
4775e2183daSJulien Grall 	_Static_assert(!is_valid_evtchn(NR_EVENT_CHANNELS),
4785e2183daSJulien Grall 	    "is_valid_evtchn(>max) fails (NOT a valid channel)");
4795e2183daSJulien Grall 	_Static_assert(!is_valid_evtchn(~(evtchn_port_t)0),
4805e2183daSJulien Grall 	    "is_valid_evtchn(maxint) fails (overflow?)");
4815e2183daSJulien Grall 	_Static_assert(!is_valid_evtchn(INVALID_EVTCHN),
4825e2183daSJulien Grall 	    "is_valid_evtchn(INVALID_EVTCHN) fails (must be invalid!)");
4835e2183daSJulien Grall 	_Static_assert(!is_valid_evtchn(-1),
4845e2183daSJulien Grall 	    "is_valid_evtchn(-1) fails (negative are invalid)");
4855e2183daSJulien Grall 
4865e2183daSJulien Grall 	mtx_init(&xen_intr_isrc_lock, "xen-irq-lock", NULL, MTX_DEF);
4875e2183daSJulien Grall 
4885e2183daSJulien Grall 	/*
4895e2183daSJulien Grall 	 * Set the per-cpu mask of CPU#0 to enable all, since by default all
4905e2183daSJulien Grall 	 * event channels are bound to CPU#0.
4915e2183daSJulien Grall 	 */
4925e2183daSJulien Grall 	CPU_FOREACH(i) {
4935e2183daSJulien Grall 		pcpu = DPCPU_ID_PTR(i, xen_intr_pcpu);
4945e2183daSJulien Grall 		memset(pcpu->evtchn_enabled, i == 0 ? ~0 : 0,
4955e2183daSJulien Grall 		    sizeof(pcpu->evtchn_enabled));
4965e2183daSJulien Grall 	}
4975e2183daSJulien Grall 
4985e2183daSJulien Grall 	for (i = 0; i < nitems(s->evtchn_mask); i++)
4994c9e6ad3SElliott Mitchell 		atomic_store_rel_xen_ulong(&s->evtchn_mask[i], ~0);
5005e2183daSJulien Grall 
5015e2183daSJulien Grall 	xen_arch_intr_init();
5025e2183daSJulien Grall 
5035e2183daSJulien Grall 	if (bootverbose)
5045e2183daSJulien Grall 		printf("Xen interrupt system initialized\n");
5055e2183daSJulien Grall 
5065e2183daSJulien Grall 	return (0);
5075e2183daSJulien Grall }
5085e2183daSJulien Grall SYSINIT(xen_intr_init, SI_SUB_INTR, SI_ORDER_SECOND, xen_intr_init, NULL);
5095e2183daSJulien Grall 
5105e2183daSJulien Grall /*--------------------------- Common PIC Functions ---------------------------*/
5115e2183daSJulien Grall 
5125e2183daSJulien Grall static void
xen_rebind_ipi(struct xenisrc * isrc)5135e2183daSJulien Grall xen_rebind_ipi(struct xenisrc *isrc)
5145e2183daSJulien Grall {
5155e2183daSJulien Grall #ifdef SMP
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_ipi bind_ipi = { .vcpu = vcpu_id };
5205e2183daSJulien Grall 
5215e2183daSJulien Grall 	error = HYPERVISOR_event_channel_op(EVTCHNOP_bind_ipi,
5225e2183daSJulien Grall 	                                    &bind_ipi);
5235e2183daSJulien Grall 	if (error != 0)
5245e2183daSJulien Grall 		panic("unable to rebind xen IPI: %d", error);
5255e2183daSJulien Grall 
5265e2183daSJulien Grall 	isrc->xi_port = bind_ipi.port;
5275e2183daSJulien Grall #else
5285e2183daSJulien Grall 	panic("Resume IPI event channel on UP");
5295e2183daSJulien Grall #endif
5305e2183daSJulien Grall }
5315e2183daSJulien Grall 
5325e2183daSJulien Grall static void
xen_rebind_virq(struct xenisrc * isrc)5335e2183daSJulien Grall xen_rebind_virq(struct xenisrc *isrc)
5345e2183daSJulien Grall {
5355e2183daSJulien Grall 	u_int cpu = isrc->xi_cpu;
5365e2183daSJulien Grall 	u_int vcpu_id = XEN_CPUID_TO_VCPUID(cpu);
5375e2183daSJulien Grall 	int error;
5385e2183daSJulien Grall 	struct evtchn_bind_virq bind_virq = { .virq = isrc->xi_virq,
5395e2183daSJulien Grall 	                                      .vcpu = vcpu_id };
5405e2183daSJulien Grall 
5415e2183daSJulien Grall 	error = HYPERVISOR_event_channel_op(EVTCHNOP_bind_virq,
5425e2183daSJulien Grall 	                                    &bind_virq);
5435e2183daSJulien Grall 	if (error != 0)
5445e2183daSJulien Grall 		panic("unable to rebind xen VIRQ#%u: %d", isrc->xi_virq, error);
5455e2183daSJulien Grall 
5465e2183daSJulien Grall 	isrc->xi_port = bind_virq.port;
5475e2183daSJulien Grall }
5485e2183daSJulien Grall 
5495e2183daSJulien Grall static struct xenisrc *
xen_intr_rebind_isrc(struct xenisrc * isrc)5505e2183daSJulien Grall xen_intr_rebind_isrc(struct xenisrc *isrc)
5515e2183daSJulien Grall {
5525e2183daSJulien Grall #ifdef SMP
5535e2183daSJulien Grall 	u_int cpu = isrc->xi_cpu;
5545e2183daSJulien Grall 	int error;
5555e2183daSJulien Grall #endif
5565e2183daSJulien Grall 	struct xenisrc *prev;
5575e2183daSJulien Grall 
5585e2183daSJulien Grall 	switch (isrc->xi_type) {
5595e2183daSJulien Grall 	case EVTCHN_TYPE_IPI:
5605e2183daSJulien Grall 		xen_rebind_ipi(isrc);
5615e2183daSJulien Grall 		break;
5625e2183daSJulien Grall 	case EVTCHN_TYPE_VIRQ:
5635e2183daSJulien Grall 		xen_rebind_virq(isrc);
5645e2183daSJulien Grall 		break;
5655e2183daSJulien Grall 	default:
5665e2183daSJulien Grall 		return (NULL);
5675e2183daSJulien Grall 	}
5685e2183daSJulien Grall 
5695e2183daSJulien Grall 	prev = xen_intr_port_to_isrc[isrc->xi_port];
5705e2183daSJulien Grall 	xen_intr_port_to_isrc[isrc->xi_port] = isrc;
5715e2183daSJulien Grall 
5725e2183daSJulien Grall #ifdef SMP
5735e2183daSJulien Grall 	isrc->xi_cpu = 0;
5745e2183daSJulien Grall 	error = xen_intr_assign_cpu(isrc, cpu);
5755e2183daSJulien Grall 	if (error)
5765e2183daSJulien Grall 		panic("%s(): unable to rebind Xen channel %u to vCPU%u: %d",
5775e2183daSJulien Grall 		    __func__, isrc->xi_port, cpu, error);
5785e2183daSJulien Grall #endif
5795e2183daSJulien Grall 
5805e2183daSJulien Grall 	evtchn_unmask_port(isrc->xi_port);
5815e2183daSJulien Grall 
5825e2183daSJulien Grall 	return (prev);
5835e2183daSJulien Grall }
5845e2183daSJulien Grall 
5855e2183daSJulien Grall /**
5865e2183daSJulien Grall  * Return this PIC to service after being suspended.
5875e2183daSJulien Grall  */
5885e2183daSJulien Grall void
xen_intr_resume(void)5895e2183daSJulien Grall xen_intr_resume(void)
5905e2183daSJulien Grall {
5915e2183daSJulien Grall 	shared_info_t *s = HYPERVISOR_shared_info;
5925e2183daSJulien Grall 	u_int isrc_idx;
5935e2183daSJulien Grall 	int i;
5945e2183daSJulien Grall 
5955e2183daSJulien Grall 	/* Reset the per-CPU masks */
5965e2183daSJulien Grall 	CPU_FOREACH(i) {
5975e2183daSJulien Grall 		struct xen_intr_pcpu_data *pcpu;
5985e2183daSJulien Grall 
5995e2183daSJulien Grall 		pcpu = DPCPU_ID_PTR(i, xen_intr_pcpu);
6005e2183daSJulien Grall 		memset(pcpu->evtchn_enabled, i == 0 ? ~0 : 0,
6015e2183daSJulien Grall 		    sizeof(pcpu->evtchn_enabled));
6025e2183daSJulien Grall 	}
6035e2183daSJulien Grall 
6045e2183daSJulien Grall 	/* Mask all event channels. */
6055e2183daSJulien Grall 	for (i = 0; i < nitems(s->evtchn_mask); i++)
6064c9e6ad3SElliott Mitchell 		atomic_store_rel_xen_ulong(&s->evtchn_mask[i], ~0);
6075e2183daSJulien Grall 
6085e2183daSJulien Grall 	/* Clear existing port mappings */
6095e2183daSJulien Grall 	for (isrc_idx = 0; isrc_idx < NR_EVENT_CHANNELS; ++isrc_idx)
6105e2183daSJulien Grall 		if (xen_intr_port_to_isrc[isrc_idx] != NULL)
6115e2183daSJulien Grall 			xen_intr_port_to_isrc[isrc_idx]->xi_port =
6125e2183daSJulien Grall 			    INVALID_EVTCHN;
6135e2183daSJulien Grall 
6145e2183daSJulien Grall 	/* Remap in-use isrcs, using xen_intr_port_to_isrc as listing */
6155e2183daSJulien Grall 	for (isrc_idx = 0; isrc_idx < NR_EVENT_CHANNELS; ++isrc_idx) {
6165e2183daSJulien Grall 		struct xenisrc *cur = xen_intr_port_to_isrc[isrc_idx];
6175e2183daSJulien Grall 
6185e2183daSJulien Grall 		/* empty or entry already taken care of */
6195e2183daSJulien Grall 		if (cur == NULL || cur->xi_port == isrc_idx)
6205e2183daSJulien Grall 			continue;
6215e2183daSJulien Grall 
6225e2183daSJulien Grall 		xen_intr_port_to_isrc[isrc_idx] = NULL;
6235e2183daSJulien Grall 
6245e2183daSJulien Grall 		do {
6255e2183daSJulien Grall 			KASSERT(!is_valid_evtchn(cur->xi_port),
6265e2183daSJulien Grall 			    ("%s(): Multiple channels on single intr?",
6275e2183daSJulien Grall 			    __func__));
6285e2183daSJulien Grall 
6295e2183daSJulien Grall 			cur = xen_intr_rebind_isrc(cur);
6305e2183daSJulien Grall 		} while (cur != NULL);
6315e2183daSJulien Grall 	}
6325e2183daSJulien Grall }
6335e2183daSJulien Grall 
6345e2183daSJulien Grall /**
6355e2183daSJulien Grall  * Disable a Xen interrupt source.
6365e2183daSJulien Grall  *
6375e2183daSJulien Grall  * \param isrc  The interrupt source to disable.
6385e2183daSJulien Grall  */
6395e2183daSJulien Grall void
xen_intr_disable_intr(struct xenisrc * isrc)6405e2183daSJulien Grall xen_intr_disable_intr(struct xenisrc *isrc)
6415e2183daSJulien Grall {
6425e2183daSJulien Grall 
6434ece7996SRoger Pau Monné 	if (__predict_true(is_valid_evtchn(isrc->xi_port)))
6445e2183daSJulien Grall 		evtchn_mask_port(isrc->xi_port);
6455e2183daSJulien Grall }
6465e2183daSJulien Grall 
6475e2183daSJulien Grall /**
6485e2183daSJulien Grall  * Configure CPU affinity for interrupt source event delivery.
6495e2183daSJulien Grall  *
6505e2183daSJulien Grall  * \param isrc     The interrupt source to configure.
6515e2183daSJulien Grall  * \param to_cpu   The id of the CPU for handling future events.
6525e2183daSJulien Grall  *
6535e2183daSJulien Grall  * \returns  0 if successful, otherwise an errno.
6545e2183daSJulien Grall  */
6555e2183daSJulien Grall int
xen_intr_assign_cpu(struct xenisrc * isrc,u_int to_cpu)6565e2183daSJulien Grall xen_intr_assign_cpu(struct xenisrc *isrc, u_int to_cpu)
6575e2183daSJulien Grall {
6585e2183daSJulien Grall #ifdef SMP
6595e2183daSJulien Grall 	struct evtchn_bind_vcpu bind_vcpu;
6605e2183daSJulien Grall 	u_int vcpu_id = XEN_CPUID_TO_VCPUID(to_cpu);
6615e2183daSJulien Grall 	int error, masked;
6625e2183daSJulien Grall 
6635e2183daSJulien Grall 	if (!xen_has_percpu_evtchn())
6645e2183daSJulien Grall 		return (EOPNOTSUPP);
6655e2183daSJulien Grall 
6665e2183daSJulien Grall 	mtx_lock(&xen_intr_isrc_lock);
6675e2183daSJulien Grall 	if (!is_valid_evtchn(isrc->xi_port)) {
6685e2183daSJulien Grall 		mtx_unlock(&xen_intr_isrc_lock);
6695e2183daSJulien Grall 		return (EINVAL);
6705e2183daSJulien Grall 	}
6715e2183daSJulien Grall 
6725e2183daSJulien Grall 	/*
6735e2183daSJulien Grall 	 * Mask the event channel while binding it to prevent interrupt
6745e2183daSJulien Grall 	 * delivery with an inconsistent state in isrc->xi_cpu.
6755e2183daSJulien Grall 	 */
6765e2183daSJulien Grall 	masked = evtchn_test_and_set_mask(isrc->xi_port);
6775e2183daSJulien Grall 	if ((isrc->xi_type == EVTCHN_TYPE_VIRQ) ||
6785e2183daSJulien Grall 		(isrc->xi_type == EVTCHN_TYPE_IPI)) {
6795e2183daSJulien Grall 		/*
6805e2183daSJulien Grall 		 * Virtual IRQs are associated with a cpu by
6815e2183daSJulien Grall 		 * the Hypervisor at evtchn_bind_virq time, so
6825e2183daSJulien Grall 		 * all we need to do is update the per-CPU masks.
6835e2183daSJulien Grall 		 */
6845e2183daSJulien Grall 		evtchn_cpu_mask_port(isrc->xi_cpu, isrc->xi_port);
6855e2183daSJulien Grall 		isrc->xi_cpu = to_cpu;
6865e2183daSJulien Grall 		evtchn_cpu_unmask_port(isrc->xi_cpu, isrc->xi_port);
6875e2183daSJulien Grall 		goto out;
6885e2183daSJulien Grall 	}
6895e2183daSJulien Grall 
6905e2183daSJulien Grall 	bind_vcpu.port = isrc->xi_port;
6915e2183daSJulien Grall 	bind_vcpu.vcpu = vcpu_id;
6925e2183daSJulien Grall 
6935e2183daSJulien Grall 	error = HYPERVISOR_event_channel_op(EVTCHNOP_bind_vcpu, &bind_vcpu);
6945e2183daSJulien Grall 	if (isrc->xi_cpu != to_cpu) {
6955e2183daSJulien Grall 		if (error == 0) {
6965e2183daSJulien Grall 			/* Commit to new binding by removing the old one. */
6975e2183daSJulien Grall 			evtchn_cpu_mask_port(isrc->xi_cpu, isrc->xi_port);
6985e2183daSJulien Grall 			isrc->xi_cpu = to_cpu;
6995e2183daSJulien Grall 			evtchn_cpu_unmask_port(isrc->xi_cpu, isrc->xi_port);
7005e2183daSJulien Grall 		}
7015e2183daSJulien Grall 	}
7025e2183daSJulien Grall 
7035e2183daSJulien Grall out:
7045e2183daSJulien Grall 	if (masked == 0)
7055e2183daSJulien Grall 		evtchn_unmask_port(isrc->xi_port);
7065e2183daSJulien Grall 	mtx_unlock(&xen_intr_isrc_lock);
7075e2183daSJulien Grall 	return (0);
7085e2183daSJulien Grall #else
7095e2183daSJulien Grall 	return (EOPNOTSUPP);
7105e2183daSJulien Grall #endif
7115e2183daSJulien Grall }
7125e2183daSJulien Grall 
7135e2183daSJulien Grall /*------------------- Virtual Interrupt Source PIC Functions -----------------*/
7145e2183daSJulien Grall /*
7155e2183daSJulien Grall  * Mask a level triggered interrupt source.
7165e2183daSJulien Grall  *
7175e2183daSJulien Grall  * \param isrc  The interrupt source to mask (if necessary).
7185e2183daSJulien Grall  */
7195e2183daSJulien Grall void
xen_intr_disable_source(struct xenisrc * isrc)7205e2183daSJulien Grall xen_intr_disable_source(struct xenisrc *isrc)
7215e2183daSJulien Grall {
7225e2183daSJulien Grall 
7235e2183daSJulien Grall 	/*
7245e2183daSJulien Grall 	 * NB: checking if the event channel is already masked is
7255e2183daSJulien Grall 	 * needed because the event channel user-space device
7265e2183daSJulien Grall 	 * masks event channels on its filter as part of its
7275e2183daSJulien Grall 	 * normal operation, and those shouldn't be automatically
7285e2183daSJulien Grall 	 * unmasked by the generic interrupt code. The event channel
7295e2183daSJulien Grall 	 * device will unmask them when needed.
7305e2183daSJulien Grall 	 */
7314ece7996SRoger Pau Monné 	if (__predict_true(is_valid_evtchn(isrc->xi_port)))
7325e2183daSJulien Grall 		isrc->xi_masked = !!evtchn_test_and_set_mask(isrc->xi_port);
7335e2183daSJulien Grall }
7345e2183daSJulien Grall 
7355e2183daSJulien Grall /*
7365e2183daSJulien Grall  * Unmask a level triggered interrupt source.
7375e2183daSJulien Grall  *
7385e2183daSJulien Grall  * \param isrc  The interrupt source to unmask (if necessary).
7395e2183daSJulien Grall  */
7405e2183daSJulien Grall void
xen_intr_enable_source(struct xenisrc * isrc)7415e2183daSJulien Grall xen_intr_enable_source(struct xenisrc *isrc)
7425e2183daSJulien Grall {
7435e2183daSJulien Grall 
7445e2183daSJulien Grall 	if (isrc->xi_masked == 0)
7455e2183daSJulien Grall 		evtchn_unmask_port(isrc->xi_port);
7465e2183daSJulien Grall }
7475e2183daSJulien Grall 
7485e2183daSJulien Grall /*
7495e2183daSJulien Grall  * Enable and unmask the interrupt source.
7505e2183daSJulien Grall  *
7515e2183daSJulien Grall  * \param isrc  The interrupt source to enable.
7525e2183daSJulien Grall  */
7535e2183daSJulien Grall void
xen_intr_enable_intr(struct xenisrc * isrc)7545e2183daSJulien Grall xen_intr_enable_intr(struct xenisrc *isrc)
7555e2183daSJulien Grall {
7565e2183daSJulien Grall 
7575e2183daSJulien Grall 	evtchn_unmask_port(isrc->xi_port);
7585e2183daSJulien Grall }
7595e2183daSJulien Grall 
7605e2183daSJulien Grall /*--------------------------- Public Functions -------------------------------*/
7615e2183daSJulien Grall /*------- API comments for these methods can be found in xen/xenintr.h -------*/
7625e2183daSJulien Grall int
xen_intr_bind_local_port(device_t dev,evtchn_port_t local_port,driver_filter_t filter,driver_intr_t handler,void * arg,enum intr_type flags,xen_intr_handle_t * port_handlep)7635e2183daSJulien Grall xen_intr_bind_local_port(device_t dev, evtchn_port_t local_port,
7645e2183daSJulien Grall     driver_filter_t filter, driver_intr_t handler, void *arg,
7655e2183daSJulien Grall     enum intr_type flags, xen_intr_handle_t *port_handlep)
7665e2183daSJulien Grall {
7675e2183daSJulien Grall 	struct xenisrc *isrc;
7685e2183daSJulien Grall 	int error;
7695e2183daSJulien Grall 
7705e2183daSJulien Grall 	error = xen_intr_bind_isrc(&isrc, local_port, EVTCHN_TYPE_PORT,
7715e2183daSJulien Grall 	    device_get_nameunit(dev), filter, handler, arg, flags,
7725e2183daSJulien Grall 	    port_handlep);
7735e2183daSJulien Grall 	if (error != 0)
7745e2183daSJulien Grall 		return (error);
7755e2183daSJulien Grall 
7765e2183daSJulien Grall 	/*
7775e2183daSJulien Grall 	 * The Event Channel API didn't open this port, so it is not
7785e2183daSJulien Grall 	 * responsible for closing it automatically on unbind.
7795e2183daSJulien Grall 	 */
7805e2183daSJulien Grall 	isrc->xi_close = 0;
7815e2183daSJulien Grall 	return (0);
7825e2183daSJulien Grall }
7835e2183daSJulien Grall 
7845e2183daSJulien Grall int
xen_intr_alloc_and_bind_local_port(device_t dev,u_int remote_domain,driver_filter_t filter,driver_intr_t handler,void * arg,enum intr_type flags,xen_intr_handle_t * port_handlep)7855e2183daSJulien Grall xen_intr_alloc_and_bind_local_port(device_t dev, u_int remote_domain,
7865e2183daSJulien Grall     driver_filter_t filter, driver_intr_t handler, void *arg,
7875e2183daSJulien Grall     enum intr_type flags, xen_intr_handle_t *port_handlep)
7885e2183daSJulien Grall {
7895e2183daSJulien Grall 	struct xenisrc *isrc;
7905e2183daSJulien Grall 	struct evtchn_alloc_unbound alloc_unbound;
7915e2183daSJulien Grall 	int error;
7925e2183daSJulien Grall 
7935e2183daSJulien Grall 	alloc_unbound.dom        = DOMID_SELF;
7945e2183daSJulien Grall 	alloc_unbound.remote_dom = remote_domain;
7955e2183daSJulien Grall 	error = HYPERVISOR_event_channel_op(EVTCHNOP_alloc_unbound,
7965e2183daSJulien Grall 		    &alloc_unbound);
7975e2183daSJulien Grall 	if (error != 0) {
7985e2183daSJulien Grall 		/*
7995e2183daSJulien Grall 		 * XXX Trap Hypercall error code Linuxisms in
8005e2183daSJulien Grall 		 *     the HYPERCALL layer.
8015e2183daSJulien Grall 		 */
8025e2183daSJulien Grall 		return (-error);
8035e2183daSJulien Grall 	}
8045e2183daSJulien Grall 
8055e2183daSJulien Grall 	error = xen_intr_bind_isrc(&isrc, alloc_unbound.port, EVTCHN_TYPE_PORT,
8065e2183daSJulien Grall 	    device_get_nameunit(dev), filter, handler, arg, flags,
8075e2183daSJulien Grall 	    port_handlep);
8085e2183daSJulien Grall 	if (error != 0) {
8095e2183daSJulien Grall 		evtchn_close_t close = { .port = alloc_unbound.port };
8105e2183daSJulien Grall 		if (HYPERVISOR_event_channel_op(EVTCHNOP_close, &close))
8115e2183daSJulien Grall 			panic("EVTCHNOP_close failed");
8125e2183daSJulien Grall 		return (error);
8135e2183daSJulien Grall 	}
8145e2183daSJulien Grall 
8155e2183daSJulien Grall 	isrc->xi_close = 1;
8165e2183daSJulien Grall 	return (0);
8175e2183daSJulien Grall }
8185e2183daSJulien Grall 
8195e2183daSJulien Grall int
xen_intr_bind_remote_port(device_t dev,u_int remote_domain,u_int remote_port,driver_filter_t filter,driver_intr_t handler,void * arg,enum intr_type flags,xen_intr_handle_t * port_handlep)8205e2183daSJulien Grall xen_intr_bind_remote_port(device_t dev, u_int remote_domain,
8215e2183daSJulien Grall     u_int remote_port, driver_filter_t filter, driver_intr_t handler,
8225e2183daSJulien Grall     void *arg, enum intr_type flags, xen_intr_handle_t *port_handlep)
8235e2183daSJulien Grall {
8245e2183daSJulien Grall 	struct xenisrc *isrc;
8255e2183daSJulien Grall 	struct evtchn_bind_interdomain bind_interdomain;
8265e2183daSJulien Grall 	int error;
8275e2183daSJulien Grall 
8285e2183daSJulien Grall 	bind_interdomain.remote_dom  = remote_domain;
8295e2183daSJulien Grall 	bind_interdomain.remote_port = remote_port;
8305e2183daSJulien Grall 	error = HYPERVISOR_event_channel_op(EVTCHNOP_bind_interdomain,
8315e2183daSJulien Grall 					    &bind_interdomain);
8325e2183daSJulien Grall 	if (error != 0) {
8335e2183daSJulien Grall 		/*
8345e2183daSJulien Grall 		 * XXX Trap Hypercall error code Linuxisms in
8355e2183daSJulien Grall 		 *     the HYPERCALL layer.
8365e2183daSJulien Grall 		 */
8375e2183daSJulien Grall 		return (-error);
8385e2183daSJulien Grall 	}
8395e2183daSJulien Grall 
8405e2183daSJulien Grall 	error = xen_intr_bind_isrc(&isrc, bind_interdomain.local_port,
8415e2183daSJulien Grall 	    EVTCHN_TYPE_PORT, device_get_nameunit(dev), filter, handler, arg,
8425e2183daSJulien Grall 	    flags, port_handlep);
8435e2183daSJulien Grall 	if (error) {
8445e2183daSJulien Grall 		evtchn_close_t close = { .port = bind_interdomain.local_port };
8455e2183daSJulien Grall 		if (HYPERVISOR_event_channel_op(EVTCHNOP_close, &close))
8465e2183daSJulien Grall 			panic("EVTCHNOP_close failed");
8475e2183daSJulien Grall 		return (error);
8485e2183daSJulien Grall 	}
8495e2183daSJulien Grall 
8505e2183daSJulien Grall 	/*
8515e2183daSJulien Grall 	 * The Event Channel API opened this port, so it is
8525e2183daSJulien Grall 	 * responsible for closing it automatically on unbind.
8535e2183daSJulien Grall 	 */
8545e2183daSJulien Grall 	isrc->xi_close = 1;
8555e2183daSJulien Grall 	return (0);
8565e2183daSJulien Grall }
8575e2183daSJulien Grall 
8585e2183daSJulien Grall int
xen_intr_bind_virq(device_t dev,u_int virq,u_int cpu,driver_filter_t filter,driver_intr_t handler,void * arg,enum intr_type flags,xen_intr_handle_t * port_handlep)8595e2183daSJulien Grall xen_intr_bind_virq(device_t dev, u_int virq, u_int cpu,
8605e2183daSJulien Grall     driver_filter_t filter, driver_intr_t handler, void *arg,
8615e2183daSJulien Grall     enum intr_type flags, xen_intr_handle_t *port_handlep)
8625e2183daSJulien Grall {
8635e2183daSJulien Grall 	u_int vcpu_id = XEN_CPUID_TO_VCPUID(cpu);
8645e2183daSJulien Grall 	struct xenisrc *isrc;
8655e2183daSJulien Grall 	struct evtchn_bind_virq bind_virq = { .virq = virq, .vcpu = vcpu_id };
8665e2183daSJulien Grall 	int error;
8675e2183daSJulien Grall 
8685e2183daSJulien Grall 	isrc = NULL;
8695e2183daSJulien Grall 	error = HYPERVISOR_event_channel_op(EVTCHNOP_bind_virq, &bind_virq);
8705e2183daSJulien Grall 	if (error != 0) {
8715e2183daSJulien Grall 		/*
8725e2183daSJulien Grall 		 * XXX Trap Hypercall error code Linuxisms in
8735e2183daSJulien Grall 		 *     the HYPERCALL layer.
8745e2183daSJulien Grall 		 */
8755e2183daSJulien Grall 		return (-error);
8765e2183daSJulien Grall 	}
8775e2183daSJulien Grall 
8785e2183daSJulien Grall 	error = xen_intr_bind_isrc(&isrc, bind_virq.port, EVTCHN_TYPE_VIRQ,
8795e2183daSJulien Grall 	    device_get_nameunit(dev), filter, handler, arg, flags,
8805e2183daSJulien Grall 	    port_handlep);
8815e2183daSJulien Grall 
8825e2183daSJulien Grall #ifdef SMP
8835e2183daSJulien Grall 	if (error == 0)
8845e2183daSJulien Grall 		error = xen_arch_intr_event_bind(isrc, cpu);
8855e2183daSJulien Grall #endif
8865e2183daSJulien Grall 
8875e2183daSJulien Grall 	if (error != 0) {
8885e2183daSJulien Grall 		evtchn_close_t close = { .port = bind_virq.port };
8895e2183daSJulien Grall 
890c880f12fSElliott Mitchell 		xen_intr_unbind(port_handlep);
8915e2183daSJulien Grall 		if (HYPERVISOR_event_channel_op(EVTCHNOP_close, &close))
8925e2183daSJulien Grall 			panic("EVTCHNOP_close failed");
8935e2183daSJulien Grall 		return (error);
8945e2183daSJulien Grall 	}
8955e2183daSJulien Grall 
8965e2183daSJulien Grall #ifdef SMP
8975e2183daSJulien Grall 	if (isrc->xi_cpu != cpu) {
8985e2183daSJulien Grall 		/*
8995e2183daSJulien Grall 		 * Too early in the boot process for the generic interrupt
9005e2183daSJulien Grall 		 * code to perform the binding.  Update our event channel
9015e2183daSJulien Grall 		 * masks manually so events can't fire on the wrong cpu
9025e2183daSJulien Grall 		 * during AP startup.
9035e2183daSJulien Grall 		 */
9045e2183daSJulien Grall 		xen_intr_assign_cpu(isrc, cpu);
9055e2183daSJulien Grall 	}
9065e2183daSJulien Grall #endif
9075e2183daSJulien Grall 
9085e2183daSJulien Grall 	/*
9095e2183daSJulien Grall 	 * The Event Channel API opened this port, so it is
9105e2183daSJulien Grall 	 * responsible for closing it automatically on unbind.
9115e2183daSJulien Grall 	 */
9125e2183daSJulien Grall 	isrc->xi_close = 1;
9135e2183daSJulien Grall 	isrc->xi_virq = virq;
9145e2183daSJulien Grall 
9155e2183daSJulien Grall 	return (0);
9165e2183daSJulien Grall }
9175e2183daSJulien Grall 
9185e2183daSJulien Grall int
xen_intr_alloc_and_bind_ipi(u_int cpu,driver_filter_t filter,enum intr_type flags,xen_intr_handle_t * port_handlep)9195e2183daSJulien Grall xen_intr_alloc_and_bind_ipi(u_int cpu, driver_filter_t filter,
9205e2183daSJulien Grall     enum intr_type flags, xen_intr_handle_t *port_handlep)
9215e2183daSJulien Grall {
9225e2183daSJulien Grall #ifdef SMP
9235e2183daSJulien Grall 	u_int vcpu_id = XEN_CPUID_TO_VCPUID(cpu);
9245e2183daSJulien Grall 	struct xenisrc *isrc;
9255e2183daSJulien Grall 	struct evtchn_bind_ipi bind_ipi = { .vcpu = vcpu_id };
9265e2183daSJulien Grall 	/* Same size as the one used by intr_handler->ih_name. */
9275e2183daSJulien Grall 	char name[MAXCOMLEN + 1];
9285e2183daSJulien Grall 	int error;
9295e2183daSJulien Grall 
9305e2183daSJulien Grall 	isrc = NULL;
9315e2183daSJulien Grall 	error = HYPERVISOR_event_channel_op(EVTCHNOP_bind_ipi, &bind_ipi);
9325e2183daSJulien Grall 	if (error != 0) {
9335e2183daSJulien Grall 		/*
9345e2183daSJulien Grall 		 * XXX Trap Hypercall error code Linuxisms in
9355e2183daSJulien Grall 		 *     the HYPERCALL layer.
9365e2183daSJulien Grall 		 */
9375e2183daSJulien Grall 		return (-error);
9385e2183daSJulien Grall 	}
9395e2183daSJulien Grall 
9405e2183daSJulien Grall 	snprintf(name, sizeof(name), "cpu%u", cpu);
9415e2183daSJulien Grall 
9425e2183daSJulien Grall 	error = xen_intr_bind_isrc(&isrc, bind_ipi.port, EVTCHN_TYPE_IPI,
9435e2183daSJulien Grall 	    name, filter, NULL, NULL, flags, port_handlep);
9445e2183daSJulien Grall 	if (error != 0) {
9455e2183daSJulien Grall 		evtchn_close_t close = { .port = bind_ipi.port };
9465e2183daSJulien Grall 
947c880f12fSElliott Mitchell 		xen_intr_unbind(port_handlep);
9485e2183daSJulien Grall 		if (HYPERVISOR_event_channel_op(EVTCHNOP_close, &close))
9495e2183daSJulien Grall 			panic("EVTCHNOP_close failed");
9505e2183daSJulien Grall 		return (error);
9515e2183daSJulien Grall 	}
9525e2183daSJulien Grall 
9535e2183daSJulien Grall 	if (isrc->xi_cpu != cpu) {
9545e2183daSJulien Grall 		/*
9555e2183daSJulien Grall 		 * Too early in the boot process for the generic interrupt
9565e2183daSJulien Grall 		 * code to perform the binding.  Update our event channel
9575e2183daSJulien Grall 		 * masks manually so events can't fire on the wrong cpu
9585e2183daSJulien Grall 		 * during AP startup.
9595e2183daSJulien Grall 		 */
9605e2183daSJulien Grall 		xen_intr_assign_cpu(isrc, cpu);
9615e2183daSJulien Grall 	}
9625e2183daSJulien Grall 
9635e2183daSJulien Grall 	/*
9645e2183daSJulien Grall 	 * The Event Channel API opened this port, so it is
9655e2183daSJulien Grall 	 * responsible for closing it automatically on unbind.
9665e2183daSJulien Grall 	 */
9675e2183daSJulien Grall 	isrc->xi_close = 1;
9685e2183daSJulien Grall 	return (0);
9695e2183daSJulien Grall #else
9705e2183daSJulien Grall 	return (EOPNOTSUPP);
9715e2183daSJulien Grall #endif
9725e2183daSJulien Grall }
9735e2183daSJulien Grall 
9745e2183daSJulien Grall int
xen_intr_describe(xen_intr_handle_t port_handle,const char * fmt,...)9755e2183daSJulien Grall xen_intr_describe(xen_intr_handle_t port_handle, const char *fmt, ...)
9765e2183daSJulien Grall {
9775e2183daSJulien Grall 	char descr[MAXCOMLEN + 1];
9785e2183daSJulien Grall 	struct xenisrc *isrc;
9795e2183daSJulien Grall 	va_list ap;
9805e2183daSJulien Grall 
9815e2183daSJulien Grall 	isrc = xen_intr_isrc_from_handle(port_handle);
9825e2183daSJulien Grall 	if (isrc == NULL)
9835e2183daSJulien Grall 		return (EINVAL);
9845e2183daSJulien Grall 
9855e2183daSJulien Grall 	va_start(ap, fmt);
9865e2183daSJulien Grall 	vsnprintf(descr, sizeof(descr), fmt, ap);
9875e2183daSJulien Grall 	va_end(ap);
9885e2183daSJulien Grall 	return (xen_arch_intr_describe(isrc, isrc->xi_cookie, descr));
9895e2183daSJulien Grall }
9905e2183daSJulien Grall 
9915e2183daSJulien Grall void
xen_intr_unbind(xen_intr_handle_t * port_handlep)9925e2183daSJulien Grall xen_intr_unbind(xen_intr_handle_t *port_handlep)
9935e2183daSJulien Grall {
9945e2183daSJulien Grall 	struct xenisrc *isrc;
9955e2183daSJulien Grall 
9965e2183daSJulien Grall 	KASSERT(port_handlep != NULL,
9975e2183daSJulien Grall 	    ("NULL xen_intr_handle_t passed to %s", __func__));
9985e2183daSJulien Grall 
9995e2183daSJulien Grall 	isrc = xen_intr_isrc_from_handle(*port_handlep);
10005e2183daSJulien Grall 	*port_handlep = NULL;
10015e2183daSJulien Grall 	if (isrc == NULL)
10025e2183daSJulien Grall 		return;
10035e2183daSJulien Grall 
10045e2183daSJulien Grall 	mtx_lock(&xen_intr_isrc_lock);
10055e2183daSJulien Grall 	if (refcount_release(&isrc->xi_refcount) == 0) {
10065e2183daSJulien Grall 		mtx_unlock(&xen_intr_isrc_lock);
10075e2183daSJulien Grall 		return;
10085e2183daSJulien Grall 	}
10095e2183daSJulien Grall 	mtx_unlock(&xen_intr_isrc_lock);
10105e2183daSJulien Grall 
10115e2183daSJulien Grall 	if (isrc->xi_cookie != NULL)
10125e2183daSJulien Grall 		xen_arch_intr_remove_handler(isrc, isrc->xi_cookie);
10135e2183daSJulien Grall 	xen_intr_release_isrc(isrc);
10145e2183daSJulien Grall }
10155e2183daSJulien Grall 
10165e2183daSJulien Grall void
xen_intr_signal(xen_intr_handle_t handle)10175e2183daSJulien Grall xen_intr_signal(xen_intr_handle_t handle)
10185e2183daSJulien Grall {
10195e2183daSJulien Grall 	struct xenisrc *isrc;
10205e2183daSJulien Grall 
10215e2183daSJulien Grall 	isrc = xen_intr_isrc_from_handle(handle);
10225e2183daSJulien Grall 	if (isrc != NULL) {
10235e2183daSJulien Grall 		KASSERT(isrc->xi_type == EVTCHN_TYPE_PORT ||
10245e2183daSJulien Grall 			isrc->xi_type == EVTCHN_TYPE_IPI,
10255e2183daSJulien Grall 			("evtchn_signal on something other than a local port"));
10265e2183daSJulien Grall 		struct evtchn_send send = { .port = isrc->xi_port };
10275e2183daSJulien Grall 		(void)HYPERVISOR_event_channel_op(EVTCHNOP_send, &send);
10285e2183daSJulien Grall 	}
10295e2183daSJulien Grall }
10305e2183daSJulien Grall 
10315e2183daSJulien Grall evtchn_port_t
xen_intr_port(xen_intr_handle_t handle)10325e2183daSJulien Grall xen_intr_port(xen_intr_handle_t handle)
10335e2183daSJulien Grall {
10345e2183daSJulien Grall 	struct xenisrc *isrc;
10355e2183daSJulien Grall 
10365e2183daSJulien Grall 	isrc = xen_intr_isrc_from_handle(handle);
10375e2183daSJulien Grall 	if (isrc == NULL)
10385e2183daSJulien Grall 		return (0);
10395e2183daSJulien Grall 
10405e2183daSJulien Grall 	return (isrc->xi_port);
10415e2183daSJulien Grall }
10425e2183daSJulien Grall 
10435e2183daSJulien Grall int
xen_intr_add_handler(const char * name,driver_filter_t filter,driver_intr_t handler,void * arg,enum intr_type flags,xen_intr_handle_t handle)10445e2183daSJulien Grall xen_intr_add_handler(const char *name, driver_filter_t filter,
10455e2183daSJulien Grall     driver_intr_t handler, void *arg, enum intr_type flags,
10465e2183daSJulien Grall     xen_intr_handle_t handle)
10475e2183daSJulien Grall {
10485e2183daSJulien Grall 	struct xenisrc *isrc;
10495e2183daSJulien Grall 	int error;
10505e2183daSJulien Grall 
10515e2183daSJulien Grall 	isrc = xen_intr_isrc_from_handle(handle);
10525e2183daSJulien Grall 	if (isrc == NULL || isrc->xi_cookie != NULL)
10535e2183daSJulien Grall 		return (EINVAL);
10545e2183daSJulien Grall 
10555e2183daSJulien Grall 	error = xen_arch_intr_add_handler(name, filter, handler, arg,
10565e2183daSJulien Grall 	    flags | INTR_EXCL, isrc, &isrc->xi_cookie);
10575e2183daSJulien Grall 	if (error != 0)
10585e2183daSJulien Grall 		printf("%s: %s: add handler failed: %d\n", name, __func__,
10595e2183daSJulien Grall 		    error);
10605e2183daSJulien Grall 
10615e2183daSJulien Grall 	return (error);
10625e2183daSJulien Grall }
10635e2183daSJulien Grall 
10645e2183daSJulien Grall int
xen_intr_get_evtchn_from_port(evtchn_port_t port,xen_intr_handle_t * handlep)10655e2183daSJulien Grall xen_intr_get_evtchn_from_port(evtchn_port_t port, xen_intr_handle_t *handlep)
10665e2183daSJulien Grall {
10675e2183daSJulien Grall 
10685e2183daSJulien Grall 	if (!is_valid_evtchn(port))
10695e2183daSJulien Grall 		return (EINVAL);
10705e2183daSJulien Grall 
10715e2183daSJulien Grall 	if (handlep == NULL) {
10725e2183daSJulien Grall 		return (EINVAL);
10735e2183daSJulien Grall 	}
10745e2183daSJulien Grall 
10755e2183daSJulien Grall 	mtx_lock(&xen_intr_isrc_lock);
10765e2183daSJulien Grall 	if (xen_intr_port_to_isrc[port] == NULL) {
10775e2183daSJulien Grall 		mtx_unlock(&xen_intr_isrc_lock);
10785e2183daSJulien Grall 		return (EINVAL);
10795e2183daSJulien Grall 	}
10805e2183daSJulien Grall 	refcount_acquire(&xen_intr_port_to_isrc[port]->xi_refcount);
10815e2183daSJulien Grall 	mtx_unlock(&xen_intr_isrc_lock);
10825e2183daSJulien Grall 
10835e2183daSJulien Grall 	/* Assign the opaque handler */
10845e2183daSJulien Grall 	*handlep = xen_intr_handle_from_isrc(xen_intr_port_to_isrc[port]);
10855e2183daSJulien Grall 
10865e2183daSJulien Grall 	return (0);
10875e2183daSJulien Grall }
10885e2183daSJulien Grall 
10895e2183daSJulien Grall #ifdef DDB
10905e2183daSJulien Grall static const char *
xen_intr_print_type(enum evtchn_type type)10915e2183daSJulien Grall xen_intr_print_type(enum evtchn_type type)
10925e2183daSJulien Grall {
10935e2183daSJulien Grall 	static const char *evtchn_type_to_string[EVTCHN_TYPE_COUNT] = {
10945e2183daSJulien Grall 		[EVTCHN_TYPE_UNBOUND]	= "UNBOUND",
10955e2183daSJulien Grall 		[EVTCHN_TYPE_VIRQ]	= "VIRQ",
10965e2183daSJulien Grall 		[EVTCHN_TYPE_IPI]	= "IPI",
10975e2183daSJulien Grall 		[EVTCHN_TYPE_PORT]	= "PORT",
10985e2183daSJulien Grall 	};
10995e2183daSJulien Grall 
11005e2183daSJulien Grall 	if (type >= EVTCHN_TYPE_COUNT)
11015e2183daSJulien Grall 		return ("UNKNOWN");
11025e2183daSJulien Grall 
11035e2183daSJulien Grall 	return (evtchn_type_to_string[type]);
11045e2183daSJulien Grall }
11055e2183daSJulien Grall 
11065e2183daSJulien Grall static void
xen_intr_dump_port(struct xenisrc * isrc)11075e2183daSJulien Grall xen_intr_dump_port(struct xenisrc *isrc)
11085e2183daSJulien Grall {
11095e2183daSJulien Grall 	struct xen_intr_pcpu_data *pcpu;
11105e2183daSJulien Grall 	shared_info_t *s = HYPERVISOR_shared_info;
11115e2183daSJulien Grall 	u_int i;
11125e2183daSJulien Grall 
11135e2183daSJulien Grall 	db_printf("Port %d Type: %s\n",
11145e2183daSJulien Grall 	    isrc->xi_port, xen_intr_print_type(isrc->xi_type));
11155e2183daSJulien Grall 	if (isrc->xi_type == EVTCHN_TYPE_VIRQ)
11165e2183daSJulien Grall 		db_printf("\tVirq: %u\n", isrc->xi_virq);
11175e2183daSJulien Grall 
11185e2183daSJulien Grall 	db_printf("\tMasked: %d Pending: %d\n",
11195e2183daSJulien Grall 	    !!xen_test_bit(isrc->xi_port, &s->evtchn_mask[0]),
11205e2183daSJulien Grall 	    !!xen_test_bit(isrc->xi_port, &s->evtchn_pending[0]));
11215e2183daSJulien Grall 
11225e2183daSJulien Grall 	db_printf("\tPer-CPU Masks: ");
11235e2183daSJulien Grall 	CPU_FOREACH(i) {
11245e2183daSJulien Grall 		pcpu = DPCPU_ID_PTR(i, xen_intr_pcpu);
11255e2183daSJulien Grall 		db_printf("cpu#%u: %d ", i,
11265e2183daSJulien Grall 		    !!xen_test_bit(isrc->xi_port, pcpu->evtchn_enabled));
11275e2183daSJulien Grall 	}
11285e2183daSJulien Grall 	db_printf("\n");
11295e2183daSJulien Grall }
11305e2183daSJulien Grall 
DB_SHOW_COMMAND(xen_evtchn,db_show_xen_evtchn)11315e2183daSJulien Grall DB_SHOW_COMMAND(xen_evtchn, db_show_xen_evtchn)
11325e2183daSJulien Grall {
11335e2183daSJulien Grall 	u_int i;
11345e2183daSJulien Grall 
11355e2183daSJulien Grall 	if (!xen_domain()) {
11365e2183daSJulien Grall 		db_printf("Only available on Xen guests\n");
11375e2183daSJulien Grall 		return;
11385e2183daSJulien Grall 	}
11395e2183daSJulien Grall 
11405e2183daSJulien Grall 	for (i = 0; i < NR_EVENT_CHANNELS; i++) {
11415e2183daSJulien Grall 		struct xenisrc *isrc;
11425e2183daSJulien Grall 
11435e2183daSJulien Grall 		isrc = xen_intr_port_to_isrc[i];
11445e2183daSJulien Grall 		if (isrc == NULL)
11455e2183daSJulien Grall 			continue;
11465e2183daSJulien Grall 
11475e2183daSJulien Grall 		xen_intr_dump_port(isrc);
11485e2183daSJulien Grall 	}
11495e2183daSJulien Grall }
11505e2183daSJulien Grall #endif /* DDB */
1151