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 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); 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 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 2045e2183daSJulien Grall xen_intr_release_isrc(struct xenisrc *isrc) 2055e2183daSJulien Grall { 2065e2183daSJulien Grall 2075e2183daSJulien Grall mtx_lock(&xen_intr_isrc_lock); 2085e2183daSJulien Grall if (is_valid_evtchn(isrc->xi_port)) { 2095e2183daSJulien Grall evtchn_mask_port(isrc->xi_port); 2105e2183daSJulien Grall evtchn_clear_port(isrc->xi_port); 2115e2183daSJulien Grall 2125e2183daSJulien Grall /* Rebind port to CPU 0. */ 2135e2183daSJulien Grall evtchn_cpu_mask_port(isrc->xi_cpu, isrc->xi_port); 2145e2183daSJulien Grall evtchn_cpu_unmask_port(0, isrc->xi_port); 2155e2183daSJulien Grall 2165e2183daSJulien Grall if (isrc->xi_close != 0) { 2175e2183daSJulien Grall struct evtchn_close close = { .port = isrc->xi_port }; 2185e2183daSJulien Grall 2195e2183daSJulien Grall if (HYPERVISOR_event_channel_op(EVTCHNOP_close, &close)) 2205e2183daSJulien Grall panic("EVTCHNOP_close failed"); 2215e2183daSJulien Grall } 2225e2183daSJulien Grall 2235e2183daSJulien Grall xen_intr_port_to_isrc[isrc->xi_port] = NULL; 2245e2183daSJulien Grall } 2255e2183daSJulien Grall /* not reachable from xen_intr_port_to_isrc[], unlock */ 2265e2183daSJulien Grall mtx_unlock(&xen_intr_isrc_lock); 2275e2183daSJulien Grall 2285e2183daSJulien Grall xen_arch_intr_release(isrc); 2295e2183daSJulien Grall return (0); 2305e2183daSJulien Grall } 2315e2183daSJulien Grall 2325e2183daSJulien Grall /** 2335e2183daSJulien Grall * Associate an interrupt handler with an already allocated local Xen 2345e2183daSJulien Grall * event channel port. 2355e2183daSJulien Grall * 2365e2183daSJulien Grall * \param isrcp The returned Xen interrupt object associated with 2375e2183daSJulien Grall * the specified local port. 2385e2183daSJulien Grall * \param local_port The event channel to bind. 2395e2183daSJulien Grall * \param type The event channel type of local_port. 2405e2183daSJulien Grall * \param intr_owner The device making this bind request. 2415e2183daSJulien Grall * \param filter An interrupt filter handler. Specify NULL 2425e2183daSJulien Grall * to always dispatch to the ithread handler. 2435e2183daSJulien Grall * \param handler An interrupt ithread handler. Optional (can 2445e2183daSJulien Grall * specify NULL) if all necessary event actions 2455e2183daSJulien Grall * are performed by filter. 2465e2183daSJulien Grall * \param arg Argument to present to both filter and handler. 2475e2183daSJulien Grall * \param irqflags Interrupt handler flags. See sys/bus.h. 2485e2183daSJulien Grall * \param handlep Pointer to an opaque handle used to manage this 2495e2183daSJulien Grall * registration. 2505e2183daSJulien Grall * 2515e2183daSJulien Grall * \returns 0 on success, otherwise an errno. 2525e2183daSJulien Grall */ 2535e2183daSJulien Grall static int 2545e2183daSJulien Grall xen_intr_bind_isrc(struct xenisrc **isrcp, evtchn_port_t local_port, 2555e2183daSJulien Grall enum evtchn_type type, const char *intr_owner, driver_filter_t filter, 2565e2183daSJulien Grall driver_intr_t handler, void *arg, enum intr_type flags, 2575e2183daSJulien Grall xen_intr_handle_t *const port_handlep) 2585e2183daSJulien Grall { 2595e2183daSJulien Grall struct xenisrc *isrc; 2605e2183daSJulien Grall int error; 2615e2183daSJulien Grall 2625e2183daSJulien Grall *isrcp = NULL; 2635e2183daSJulien Grall if (port_handlep == NULL) { 2645e2183daSJulien Grall printf("%s: %s: Bad event handle\n", intr_owner, __func__); 2655e2183daSJulien Grall return (EINVAL); 2665e2183daSJulien Grall } 2675e2183daSJulien Grall *port_handlep = NULL; 2685e2183daSJulien Grall 2695e2183daSJulien Grall isrc = xen_arch_intr_alloc(); 2705e2183daSJulien Grall if (isrc == NULL) 2715e2183daSJulien Grall return (ENOSPC); 2725e2183daSJulien Grall 2735e2183daSJulien Grall isrc->xi_cookie = NULL; 2745e2183daSJulien Grall isrc->xi_type = type; 2755e2183daSJulien Grall isrc->xi_port = local_port; 2765e2183daSJulien Grall isrc->xi_close = false; 2775e2183daSJulien Grall isrc->xi_cpu = 0; 2785e2183daSJulien Grall refcount_init(&isrc->xi_refcount, 1); 2795e2183daSJulien Grall mtx_lock(&xen_intr_isrc_lock); 2805e2183daSJulien Grall xen_intr_port_to_isrc[isrc->xi_port] = isrc; 2815e2183daSJulien Grall mtx_unlock(&xen_intr_isrc_lock); 2825e2183daSJulien Grall 2835e2183daSJulien Grall #ifdef SMP 2845e2183daSJulien Grall if (type == EVTCHN_TYPE_PORT) { 2855e2183daSJulien Grall /* 2865e2183daSJulien Grall * By default all interrupts are assigned to vCPU#0 2875e2183daSJulien Grall * unless specified otherwise, so shuffle them to balance 2885e2183daSJulien Grall * the interrupt load. 2895e2183daSJulien Grall */ 2905e2183daSJulien Grall xen_intr_assign_cpu(isrc, xen_arch_intr_next_cpu(isrc)); 2915e2183daSJulien Grall } 2925e2183daSJulien Grall #endif 2935e2183daSJulien Grall 2945e2183daSJulien Grall /* 2955e2183daSJulien Grall * If a filter or handler function is provided, add it to the event. 2965e2183daSJulien Grall * Otherwise the event channel is left masked and without a handler, 2975e2183daSJulien Grall * the caller is in charge of setting that up. 2985e2183daSJulien Grall */ 2995e2183daSJulien Grall if (filter != NULL || handler != NULL) { 3005e2183daSJulien Grall error = xen_intr_add_handler(intr_owner, filter, handler, arg, 3015e2183daSJulien Grall flags, xen_intr_handle_from_isrc(isrc)); 3025e2183daSJulien Grall if (error != 0) { 3035e2183daSJulien Grall xen_intr_release_isrc(isrc); 3045e2183daSJulien Grall return (error); 3055e2183daSJulien Grall } 3065e2183daSJulien Grall } 3075e2183daSJulien Grall 3085e2183daSJulien Grall *isrcp = isrc; 3095e2183daSJulien Grall /* Assign the opaque handler */ 3105e2183daSJulien Grall *port_handlep = xen_intr_handle_from_isrc(isrc); 3115e2183daSJulien Grall return (0); 3125e2183daSJulien Grall } 3135e2183daSJulien Grall 3145e2183daSJulien Grall /** 3155e2183daSJulien Grall * Determine the event channel ports at the given section of the 3165e2183daSJulien Grall * event port bitmap which have pending events for the given cpu. 3175e2183daSJulien Grall * 3185e2183daSJulien Grall * \param pcpu The Xen interrupt pcpu data for the cpu being queried. 3195e2183daSJulien Grall * \param sh The Xen shared info area. 3205e2183daSJulien Grall * \param idx The index of the section of the event channel bitmap to 3215e2183daSJulien Grall * inspect. 3225e2183daSJulien Grall * 3235e2183daSJulien Grall * \returns A u_long with bits set for every event channel with pending 3245e2183daSJulien Grall * events. 3255e2183daSJulien Grall */ 3265e2183daSJulien Grall static inline u_long 3275e2183daSJulien Grall xen_intr_active_ports(const struct xen_intr_pcpu_data *const pcpu, 3285e2183daSJulien Grall const u_int idx) 3295e2183daSJulien Grall { 3305e2183daSJulien Grall volatile const shared_info_t *const sh = HYPERVISOR_shared_info; 3315e2183daSJulien Grall 3325e2183daSJulien Grall CTASSERT(sizeof(sh->evtchn_mask[0]) == sizeof(sh->evtchn_pending[0])); 3335e2183daSJulien Grall CTASSERT(sizeof(sh->evtchn_mask[0]) == sizeof(pcpu->evtchn_enabled[0])); 3345e2183daSJulien Grall CTASSERT(sizeof(sh->evtchn_mask) == sizeof(sh->evtchn_pending)); 3355e2183daSJulien Grall CTASSERT(sizeof(sh->evtchn_mask) == sizeof(pcpu->evtchn_enabled)); 3365e2183daSJulien Grall return (sh->evtchn_pending[idx] 3375e2183daSJulien Grall & ~sh->evtchn_mask[idx] 3385e2183daSJulien Grall & pcpu->evtchn_enabled[idx]); 3395e2183daSJulien Grall } 3405e2183daSJulien Grall 3415e2183daSJulien Grall /** 3425e2183daSJulien Grall * Interrupt handler for processing all Xen event channel events. 3435e2183daSJulien Grall * 344*f750dce9SRoger Pau Monné * \param unused 3455e2183daSJulien Grall */ 3465e2183daSJulien Grall int 3475e2183daSJulien Grall xen_intr_handle_upcall(void *unused __unused) 3485e2183daSJulien Grall { 3495e2183daSJulien Grall struct trapframe *trap_frame = curthread->td_intr_frame; 3505e2183daSJulien Grall u_int l1i, l2i, port, cpu __diagused; 3515e2183daSJulien Grall u_long masked_l1, masked_l2; 3525e2183daSJulien Grall struct xenisrc *isrc; 3535e2183daSJulien Grall vcpu_info_t *v; 3545e2183daSJulien Grall struct xen_intr_pcpu_data *pc; 3555e2183daSJulien Grall u_long l1, l2; 3565e2183daSJulien Grall 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 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 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 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 * 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 * 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 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 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