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