1273474Sroyger/****************************************************************************** 2273474Sroyger * evtchn.c 3273474Sroyger * 4273474Sroyger * Driver for receiving and demuxing event-channel signals. 5273474Sroyger * 6273474Sroyger * Copyright (c) 2004-2005, K A Fraser 7273474Sroyger * Multi-process extensions Copyright (c) 2004, Steven Smith 8273474Sroyger * FreeBSD port Copyright (c) 2014, Roger Pau Monn�� 9273474Sroyger * Fetched from git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git 10273474Sroyger * File: drivers/xen/evtchn.c 11273474Sroyger * Git commit: 0dc0064add422bc0ef5165ebe9ece3052bbd457d 12273474Sroyger * 13273474Sroyger * This program is free software; you can redistribute it and/or 14273474Sroyger * modify it under the terms of the GNU General Public License version 2 15273474Sroyger * as published by the Free Software Foundation; or, when distributed 16273474Sroyger * separately from the Linux kernel or incorporated into other 17273474Sroyger * software packages, subject to the following license: 18273474Sroyger * 19273474Sroyger * Permission is hereby granted, free of charge, to any person obtaining a copy 20273474Sroyger * of this source file (the "Software"), to deal in the Software without 21273474Sroyger * restriction, including without limitation the rights to use, copy, modify, 22273474Sroyger * merge, publish, distribute, sublicense, and/or sell copies of the Software, 23273474Sroyger * and to permit persons to whom the Software is furnished to do so, subject to 24273474Sroyger * the following conditions: 25273474Sroyger * 26273474Sroyger * The above copyright notice and this permission notice shall be included in 27273474Sroyger * all copies or substantial portions of the Software. 28273474Sroyger * 29273474Sroyger * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 30273474Sroyger * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 31273474Sroyger * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 32273474Sroyger * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 33273474Sroyger * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 34273474Sroyger * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 35273474Sroyger * IN THE SOFTWARE. 36273474Sroyger */ 37273474Sroyger 38273474Sroyger#include <sys/cdefs.h> 39273474Sroyger__FBSDID("$FreeBSD: releng/11.0/sys/dev/xen/evtchn/evtchn_dev.c 299353 2016-05-10 10:26:07Z trasz $"); 40273474Sroyger 41273474Sroyger#include <sys/param.h> 42273474Sroyger#include <sys/systm.h> 43273474Sroyger#include <sys/uio.h> 44273474Sroyger#include <sys/bus.h> 45273474Sroyger#include <sys/malloc.h> 46273474Sroyger#include <sys/kernel.h> 47273474Sroyger#include <sys/lock.h> 48273474Sroyger#include <sys/mutex.h> 49273474Sroyger#include <sys/sx.h> 50273474Sroyger#include <sys/selinfo.h> 51273474Sroyger#include <sys/poll.h> 52273474Sroyger#include <sys/conf.h> 53273474Sroyger#include <sys/fcntl.h> 54273474Sroyger#include <sys/ioccom.h> 55273474Sroyger#include <sys/rman.h> 56273474Sroyger#include <sys/tree.h> 57273474Sroyger#include <sys/module.h> 58273474Sroyger#include <sys/filio.h> 59273474Sroyger#include <sys/vnode.h> 60273474Sroyger 61273474Sroyger#include <machine/intr_machdep.h> 62273474Sroyger#include <machine/xen/synch_bitops.h> 63273474Sroyger 64273474Sroyger#include <xen/xen-os.h> 65273474Sroyger#include <xen/evtchn.h> 66273474Sroyger#include <xen/xen_intr.h> 67273474Sroyger 68273474Sroyger#include <xen/evtchn/evtchnvar.h> 69273474Sroyger 70273474SroygerMALLOC_DEFINE(M_EVTCHN, "evtchn_dev", "Xen event channel user-space device"); 71273474Sroyger 72273474Sroygerstruct user_evtchn; 73273474Sroyger 74273474Sroygerstatic int evtchn_cmp(struct user_evtchn *u1, struct user_evtchn *u2); 75273474Sroyger 76273474SroygerRB_HEAD(evtchn_tree, user_evtchn); 77273474Sroyger 78273474Sroygerstruct per_user_data { 79273474Sroyger struct mtx bind_mutex; /* serialize bind/unbind operations */ 80273474Sroyger struct evtchn_tree evtchns; 81273474Sroyger 82273474Sroyger /* Notification ring, accessed via /dev/xen/evtchn. */ 83273474Sroyger#define EVTCHN_RING_SIZE (PAGE_SIZE / sizeof(evtchn_port_t)) 84273474Sroyger#define EVTCHN_RING_MASK(_i) ((_i)&(EVTCHN_RING_SIZE-1)) 85273474Sroyger evtchn_port_t *ring; 86273474Sroyger unsigned int ring_cons, ring_prod, ring_overflow; 87273474Sroyger struct sx ring_cons_mutex; /* protect against concurrent readers */ 88273474Sroyger struct mtx ring_prod_mutex; /* product against concurrent interrupts */ 89273474Sroyger struct selinfo ev_rsel; 90273474Sroyger}; 91273474Sroyger 92273474Sroygerstruct user_evtchn { 93273474Sroyger RB_ENTRY(user_evtchn) node; 94273474Sroyger struct per_user_data *user; 95273474Sroyger evtchn_port_t port; 96273474Sroyger xen_intr_handle_t handle; 97273474Sroyger bool enabled; 98273474Sroyger}; 99273474Sroyger 100273474SroygerRB_GENERATE_STATIC(evtchn_tree, user_evtchn, node, evtchn_cmp); 101273474Sroyger 102273474Sroygerstatic device_t evtchn_dev; 103273474Sroyger 104273474Sroygerstatic d_read_t evtchn_read; 105273474Sroygerstatic d_write_t evtchn_write; 106273474Sroygerstatic d_ioctl_t evtchn_ioctl; 107273474Sroygerstatic d_poll_t evtchn_poll; 108273474Sroygerstatic d_open_t evtchn_open; 109273474Sroyger 110273474Sroygerstatic void evtchn_release(void *arg); 111273474Sroyger 112273474Sroygerstatic struct cdevsw evtchn_devsw = { 113273474Sroyger .d_version = D_VERSION, 114273474Sroyger .d_open = evtchn_open, 115273474Sroyger .d_read = evtchn_read, 116273474Sroyger .d_write = evtchn_write, 117273474Sroyger .d_ioctl = evtchn_ioctl, 118273474Sroyger .d_poll = evtchn_poll, 119273474Sroyger .d_name = "evtchn", 120273474Sroyger}; 121273474Sroyger 122273474Sroyger/*------------------------- Red-black tree helpers ---------------------------*/ 123273474Sroygerstatic int 124273474Sroygerevtchn_cmp(struct user_evtchn *u1, struct user_evtchn *u2) 125273474Sroyger{ 126273474Sroyger 127273474Sroyger return (u1->port - u2->port); 128273474Sroyger} 129273474Sroyger 130273474Sroygerstatic struct user_evtchn * 131273474Sroygerfind_evtchn(struct per_user_data *u, evtchn_port_t port) 132273474Sroyger{ 133273474Sroyger struct user_evtchn tmp = { 134273474Sroyger .port = port, 135273474Sroyger }; 136273474Sroyger 137273474Sroyger return (RB_FIND(evtchn_tree, &u->evtchns, &tmp)); 138273474Sroyger} 139273474Sroyger 140273474Sroyger/*--------------------------- Interrupt handlers -----------------------------*/ 141273474Sroygerstatic int 142273474Sroygerevtchn_filter(void *arg) 143273474Sroyger{ 144273474Sroyger struct user_evtchn *evtchn; 145273474Sroyger 146273474Sroyger evtchn = arg; 147273474Sroyger 148273474Sroyger if (!evtchn->enabled && bootverbose) { 149273474Sroyger device_printf(evtchn_dev, 150273474Sroyger "Received upcall for disabled event channel %d\n", 151273474Sroyger evtchn->port); 152273474Sroyger } 153273474Sroyger 154273474Sroyger evtchn_mask_port(evtchn->port); 155273474Sroyger evtchn->enabled = false; 156273474Sroyger 157273474Sroyger return (FILTER_SCHEDULE_THREAD); 158273474Sroyger} 159273474Sroyger 160273474Sroygerstatic void 161273474Sroygerevtchn_interrupt(void *arg) 162273474Sroyger{ 163273474Sroyger struct user_evtchn *evtchn; 164273474Sroyger struct per_user_data *u; 165273474Sroyger 166273474Sroyger evtchn = arg; 167273474Sroyger u = evtchn->user; 168273474Sroyger 169273474Sroyger /* 170273474Sroyger * Protect against concurrent events using this handler 171273474Sroyger * on different CPUs. 172273474Sroyger */ 173273474Sroyger mtx_lock(&u->ring_prod_mutex); 174273474Sroyger if ((u->ring_prod - u->ring_cons) < EVTCHN_RING_SIZE) { 175273474Sroyger u->ring[EVTCHN_RING_MASK(u->ring_prod)] = evtchn->port; 176273474Sroyger wmb(); /* Ensure ring contents visible */ 177273474Sroyger if (u->ring_cons == u->ring_prod++) { 178273474Sroyger wakeup(u); 179273474Sroyger selwakeup(&u->ev_rsel); 180273474Sroyger } 181273474Sroyger } else 182273474Sroyger u->ring_overflow = 1; 183273474Sroyger mtx_unlock(&u->ring_prod_mutex); 184273474Sroyger} 185273474Sroyger 186273474Sroyger/*------------------------- Character device methods -------------------------*/ 187273474Sroygerstatic int 188273474Sroygerevtchn_open(struct cdev *dev, int flag, int otyp, struct thread *td) 189273474Sroyger{ 190273474Sroyger struct per_user_data *u; 191273474Sroyger int error; 192273474Sroyger 193273474Sroyger u = malloc(sizeof(*u), M_EVTCHN, M_WAITOK | M_ZERO); 194273474Sroyger u->ring = malloc(PAGE_SIZE, M_EVTCHN, M_WAITOK | M_ZERO); 195273474Sroyger 196273474Sroyger /* Initialize locks */ 197273474Sroyger mtx_init(&u->bind_mutex, "evtchn_bind_mutex", NULL, MTX_DEF); 198273474Sroyger sx_init(&u->ring_cons_mutex, "evtchn_ringc_sx"); 199273474Sroyger mtx_init(&u->ring_prod_mutex, "evtchn_ringp_mutex", NULL, MTX_DEF); 200273474Sroyger 201273474Sroyger /* Initialize red-black tree. */ 202273474Sroyger RB_INIT(&u->evtchns); 203273474Sroyger 204273474Sroyger /* Assign the allocated per_user_data to this open instance. */ 205273474Sroyger error = devfs_set_cdevpriv(u, evtchn_release); 206273474Sroyger if (error != 0) { 207273474Sroyger mtx_destroy(&u->bind_mutex); 208273474Sroyger mtx_destroy(&u->ring_prod_mutex); 209273474Sroyger sx_destroy(&u->ring_cons_mutex); 210273474Sroyger free(u->ring, M_EVTCHN); 211273474Sroyger free(u, M_EVTCHN); 212273474Sroyger } 213273474Sroyger 214273474Sroyger return (error); 215273474Sroyger} 216273474Sroyger 217273474Sroygerstatic void 218273474Sroygerevtchn_release(void *arg) 219273474Sroyger{ 220273474Sroyger struct per_user_data *u; 221273474Sroyger struct user_evtchn *evtchn, *tmp; 222273474Sroyger 223273474Sroyger u = arg; 224273474Sroyger 225273474Sroyger seldrain(&u->ev_rsel); 226273474Sroyger 227273474Sroyger RB_FOREACH_SAFE(evtchn, evtchn_tree, &u->evtchns, tmp) { 228273474Sroyger xen_intr_unbind(&evtchn->handle); 229273474Sroyger 230273474Sroyger RB_REMOVE(evtchn_tree, &u->evtchns, evtchn); 231273474Sroyger free(evtchn, M_EVTCHN); 232273474Sroyger } 233273474Sroyger 234273474Sroyger mtx_destroy(&u->bind_mutex); 235273474Sroyger mtx_destroy(&u->ring_prod_mutex); 236273474Sroyger sx_destroy(&u->ring_cons_mutex); 237273474Sroyger free(u->ring, M_EVTCHN); 238273474Sroyger free(u, M_EVTCHN); 239273474Sroyger} 240273474Sroyger 241273474Sroygerstatic int 242273474Sroygerevtchn_read(struct cdev *dev, struct uio *uio, int ioflag) 243273474Sroyger{ 244273474Sroyger int error, count; 245273474Sroyger unsigned int c, p, bytes1 = 0, bytes2 = 0; 246273474Sroyger struct per_user_data *u; 247273474Sroyger 248273474Sroyger error = devfs_get_cdevpriv((void **)&u); 249273474Sroyger if (error != 0) 250273474Sroyger return (EINVAL); 251273474Sroyger 252273474Sroyger /* Whole number of ports. */ 253273474Sroyger count = uio->uio_resid; 254273474Sroyger count &= ~(sizeof(evtchn_port_t)-1); 255273474Sroyger 256273474Sroyger if (count == 0) 257273474Sroyger return (0); 258273474Sroyger 259273474Sroyger if (count > PAGE_SIZE) 260273474Sroyger count = PAGE_SIZE; 261273474Sroyger 262273474Sroyger sx_xlock(&u->ring_cons_mutex); 263273474Sroyger for (;;) { 264273474Sroyger error = EFBIG; 265273474Sroyger if (u->ring_overflow) 266273474Sroyger goto unlock_out; 267273474Sroyger 268273474Sroyger c = u->ring_cons; 269273474Sroyger p = u->ring_prod; 270273474Sroyger if (c != p) 271273474Sroyger break; 272273474Sroyger 273273474Sroyger if (ioflag & IO_NDELAY) { 274273474Sroyger sx_xunlock(&u->ring_cons_mutex); 275273474Sroyger return (EWOULDBLOCK); 276273474Sroyger } 277273474Sroyger 278273474Sroyger error = sx_sleep(u, &u->ring_cons_mutex, PCATCH, "evtchw", 0); 279273474Sroyger if ((error != 0) && (error != EWOULDBLOCK)) 280273474Sroyger return (error); 281273474Sroyger } 282273474Sroyger 283273474Sroyger /* Byte lengths of two chunks. Chunk split (if any) is at ring wrap. */ 284273474Sroyger if (((c ^ p) & EVTCHN_RING_SIZE) != 0) { 285273474Sroyger bytes1 = (EVTCHN_RING_SIZE - EVTCHN_RING_MASK(c)) * 286273474Sroyger sizeof(evtchn_port_t); 287273474Sroyger bytes2 = EVTCHN_RING_MASK(p) * sizeof(evtchn_port_t); 288273474Sroyger } else { 289273474Sroyger bytes1 = (p - c) * sizeof(evtchn_port_t); 290273474Sroyger bytes2 = 0; 291273474Sroyger } 292273474Sroyger 293273474Sroyger /* Truncate chunks according to caller's maximum byte count. */ 294273474Sroyger if (bytes1 > count) { 295273474Sroyger bytes1 = count; 296273474Sroyger bytes2 = 0; 297273474Sroyger } else if ((bytes1 + bytes2) > count) { 298273474Sroyger bytes2 = count - bytes1; 299273474Sroyger } 300273474Sroyger 301273474Sroyger error = EFAULT; 302273474Sroyger rmb(); /* Ensure that we see the port before we copy it. */ 303273474Sroyger 304273474Sroyger if (uiomove(&u->ring[EVTCHN_RING_MASK(c)], bytes1, uio) || 305273474Sroyger ((bytes2 != 0) && uiomove(&u->ring[0], bytes2, uio))) 306273474Sroyger goto unlock_out; 307273474Sroyger 308273474Sroyger u->ring_cons += (bytes1 + bytes2) / sizeof(evtchn_port_t); 309273474Sroyger error = 0; 310273474Sroyger 311273474Sroygerunlock_out: 312273474Sroyger sx_xunlock(&u->ring_cons_mutex); 313273474Sroyger return (error); 314273474Sroyger} 315273474Sroyger 316273474Sroygerstatic int 317273474Sroygerevtchn_write(struct cdev *dev, struct uio *uio, int ioflag) 318273474Sroyger{ 319273474Sroyger int error, i, count; 320273474Sroyger evtchn_port_t *kbuf; 321273474Sroyger struct per_user_data *u; 322273474Sroyger 323273474Sroyger error = devfs_get_cdevpriv((void **)&u); 324273474Sroyger if (error != 0) 325273474Sroyger return (EINVAL); 326273474Sroyger 327273474Sroyger kbuf = malloc(PAGE_SIZE, M_EVTCHN, M_WAITOK); 328273474Sroyger 329273474Sroyger count = uio->uio_resid; 330273474Sroyger /* Whole number of ports. */ 331273474Sroyger count &= ~(sizeof(evtchn_port_t)-1); 332273474Sroyger 333273474Sroyger error = 0; 334273474Sroyger if (count == 0) 335273474Sroyger goto out; 336273474Sroyger 337273474Sroyger if (count > PAGE_SIZE) 338273474Sroyger count = PAGE_SIZE; 339273474Sroyger 340273474Sroyger error = uiomove(kbuf, count, uio); 341273474Sroyger if (error != 0) 342273474Sroyger goto out; 343273474Sroyger 344273474Sroyger mtx_lock(&u->bind_mutex); 345273474Sroyger 346273474Sroyger for (i = 0; i < (count/sizeof(evtchn_port_t)); i++) { 347273474Sroyger evtchn_port_t port = kbuf[i]; 348273474Sroyger struct user_evtchn *evtchn; 349273474Sroyger 350273474Sroyger evtchn = find_evtchn(u, port); 351273474Sroyger if (evtchn && !evtchn->enabled) { 352273474Sroyger evtchn->enabled = true; 353273474Sroyger evtchn_unmask_port(evtchn->port); 354273474Sroyger } 355273474Sroyger } 356273474Sroyger 357273474Sroyger mtx_unlock(&u->bind_mutex); 358273474Sroyger error = 0; 359273474Sroyger 360273474Sroygerout: 361273474Sroyger free(kbuf, M_EVTCHN); 362273474Sroyger return (error); 363273474Sroyger} 364273474Sroyger 365273474Sroygerstatic inline int 366273474Sroygerevtchn_bind_user_port(struct per_user_data *u, struct user_evtchn *evtchn) 367273474Sroyger{ 368273474Sroyger int error; 369273474Sroyger 370273474Sroyger evtchn->port = xen_intr_port(evtchn->handle); 371273474Sroyger evtchn->user = u; 372273474Sroyger evtchn->enabled = true; 373273474Sroyger mtx_lock(&u->bind_mutex); 374273474Sroyger RB_INSERT(evtchn_tree, &u->evtchns, evtchn); 375273474Sroyger mtx_unlock(&u->bind_mutex); 376273474Sroyger error = xen_intr_add_handler(evtchn_dev, evtchn_filter, 377273474Sroyger evtchn_interrupt, evtchn, INTR_TYPE_MISC | INTR_MPSAFE, 378273474Sroyger evtchn->handle); 379273474Sroyger if (error != 0) { 380273474Sroyger xen_intr_unbind(&evtchn->handle); 381273474Sroyger mtx_lock(&u->bind_mutex); 382273474Sroyger RB_REMOVE(evtchn_tree, &u->evtchns, evtchn); 383273474Sroyger mtx_unlock(&u->bind_mutex); 384273474Sroyger free(evtchn, M_EVTCHN); 385273474Sroyger } 386273474Sroyger return (error); 387273474Sroyger} 388273474Sroyger 389273474Sroygerstatic int 390273474Sroygerevtchn_ioctl(struct cdev *dev, unsigned long cmd, caddr_t arg, 391273474Sroyger int mode, struct thread *td __unused) 392273474Sroyger{ 393273474Sroyger struct per_user_data *u; 394273474Sroyger int error; 395273474Sroyger 396273474Sroyger error = devfs_get_cdevpriv((void **)&u); 397273474Sroyger if (error != 0) 398273474Sroyger return (EINVAL); 399273474Sroyger 400273474Sroyger switch (cmd) { 401273474Sroyger case IOCTL_EVTCHN_BIND_VIRQ: { 402273474Sroyger struct ioctl_evtchn_bind_virq *bind; 403273474Sroyger struct user_evtchn *evtchn; 404273474Sroyger 405273474Sroyger evtchn = malloc(sizeof(*evtchn), M_EVTCHN, M_WAITOK | M_ZERO); 406273474Sroyger 407273474Sroyger bind = (struct ioctl_evtchn_bind_virq *)arg; 408273474Sroyger 409273474Sroyger error = xen_intr_bind_virq(evtchn_dev, bind->virq, 0, 410273474Sroyger NULL, NULL, NULL, 0, &evtchn->handle); 411273474Sroyger if (error != 0) { 412273474Sroyger free(evtchn, M_EVTCHN); 413273474Sroyger break; 414273474Sroyger } 415273474Sroyger error = evtchn_bind_user_port(u, evtchn); 416273474Sroyger if (error != 0) 417273474Sroyger break; 418273474Sroyger bind->port = evtchn->port; 419273474Sroyger break; 420273474Sroyger } 421273474Sroyger 422273474Sroyger case IOCTL_EVTCHN_BIND_INTERDOMAIN: { 423273474Sroyger struct ioctl_evtchn_bind_interdomain *bind; 424273474Sroyger struct user_evtchn *evtchn; 425273474Sroyger 426273474Sroyger evtchn = malloc(sizeof(*evtchn), M_EVTCHN, M_WAITOK | M_ZERO); 427273474Sroyger 428273474Sroyger bind = (struct ioctl_evtchn_bind_interdomain *)arg; 429273474Sroyger 430273474Sroyger error = xen_intr_bind_remote_port(evtchn_dev, 431273474Sroyger bind->remote_domain, bind->remote_port, NULL, 432273474Sroyger NULL, NULL, 0, &evtchn->handle); 433273474Sroyger if (error != 0) { 434273474Sroyger free(evtchn, M_EVTCHN); 435273474Sroyger break; 436273474Sroyger } 437273474Sroyger error = evtchn_bind_user_port(u, evtchn); 438273474Sroyger if (error != 0) 439273474Sroyger break; 440273474Sroyger bind->port = evtchn->port; 441273474Sroyger break; 442273474Sroyger } 443273474Sroyger 444273474Sroyger case IOCTL_EVTCHN_BIND_UNBOUND_PORT: { 445273474Sroyger struct ioctl_evtchn_bind_unbound_port *bind; 446273474Sroyger struct user_evtchn *evtchn; 447273474Sroyger 448273474Sroyger evtchn = malloc(sizeof(*evtchn), M_EVTCHN, M_WAITOK | M_ZERO); 449273474Sroyger 450273474Sroyger bind = (struct ioctl_evtchn_bind_unbound_port *)arg; 451273474Sroyger 452273474Sroyger error = xen_intr_alloc_and_bind_local_port(evtchn_dev, 453273474Sroyger bind->remote_domain, NULL, NULL, NULL, 0, &evtchn->handle); 454273474Sroyger if (error != 0) { 455273474Sroyger free(evtchn, M_EVTCHN); 456273474Sroyger break; 457273474Sroyger } 458273474Sroyger error = evtchn_bind_user_port(u, evtchn); 459273474Sroyger if (error != 0) 460273474Sroyger break; 461273474Sroyger bind->port = evtchn->port; 462273474Sroyger break; 463273474Sroyger } 464273474Sroyger 465273474Sroyger case IOCTL_EVTCHN_UNBIND: { 466273474Sroyger struct ioctl_evtchn_unbind *unbind; 467273474Sroyger struct user_evtchn *evtchn; 468273474Sroyger 469273474Sroyger unbind = (struct ioctl_evtchn_unbind *)arg; 470273474Sroyger 471273474Sroyger mtx_lock(&u->bind_mutex); 472273474Sroyger evtchn = find_evtchn(u, unbind->port); 473273474Sroyger if (evtchn == NULL) { 474273474Sroyger error = ENOTCONN; 475273474Sroyger break; 476273474Sroyger } 477273474Sroyger 478273474Sroyger xen_intr_unbind(&evtchn->handle); 479273474Sroyger RB_REMOVE(evtchn_tree, &u->evtchns, evtchn); 480273474Sroyger mtx_unlock(&u->bind_mutex); 481273474Sroyger free(evtchn, M_EVTCHN); 482273474Sroyger error = 0; 483273474Sroyger break; 484273474Sroyger } 485273474Sroyger 486273474Sroyger case IOCTL_EVTCHN_NOTIFY: { 487273474Sroyger struct ioctl_evtchn_notify *notify; 488273474Sroyger struct user_evtchn *evtchn; 489273474Sroyger 490273474Sroyger notify = (struct ioctl_evtchn_notify *)arg; 491273474Sroyger 492273474Sroyger mtx_lock(&u->bind_mutex); 493273474Sroyger evtchn = find_evtchn(u, notify->port); 494273474Sroyger if (evtchn == NULL) { 495273474Sroyger error = ENOTCONN; 496273474Sroyger break; 497273474Sroyger } 498273474Sroyger 499273474Sroyger xen_intr_signal(evtchn->handle); 500273474Sroyger mtx_unlock(&u->bind_mutex); 501273474Sroyger error = 0; 502273474Sroyger break; 503273474Sroyger } 504273474Sroyger 505273474Sroyger case IOCTL_EVTCHN_RESET: { 506273474Sroyger /* Initialise the ring to empty. Clear errors. */ 507273474Sroyger sx_xlock(&u->ring_cons_mutex); 508273474Sroyger mtx_lock(&u->ring_prod_mutex); 509273474Sroyger u->ring_cons = u->ring_prod = u->ring_overflow = 0; 510273474Sroyger mtx_unlock(&u->ring_prod_mutex); 511273474Sroyger sx_xunlock(&u->ring_cons_mutex); 512273474Sroyger error = 0; 513273474Sroyger break; 514273474Sroyger } 515273474Sroyger 516273474Sroyger case FIONBIO: 517273474Sroyger case FIOASYNC: 518273474Sroyger /* Handled in an upper layer */ 519273474Sroyger error = 0; 520273474Sroyger break; 521273474Sroyger 522273474Sroyger default: 523273474Sroyger error = ENOTTY; 524273474Sroyger break; 525273474Sroyger } 526273474Sroyger 527273474Sroyger return (error); 528273474Sroyger} 529273474Sroyger 530273474Sroygerstatic int 531273474Sroygerevtchn_poll(struct cdev *dev, int events, struct thread *td) 532273474Sroyger{ 533273474Sroyger struct per_user_data *u; 534273474Sroyger int error, mask; 535273474Sroyger 536273474Sroyger error = devfs_get_cdevpriv((void **)&u); 537273474Sroyger if (error != 0) 538273474Sroyger return (POLLERR); 539273474Sroyger 540273474Sroyger /* we can always write */ 541273474Sroyger mask = events & (POLLOUT | POLLWRNORM); 542273474Sroyger 543273474Sroyger mtx_lock(&u->ring_prod_mutex); 544273474Sroyger if (events & (POLLIN | POLLRDNORM)) { 545273474Sroyger if (u->ring_cons != u->ring_prod) { 546273474Sroyger mask |= events & (POLLIN | POLLRDNORM); 547273474Sroyger } else { 548273474Sroyger /* Record that someone is waiting */ 549273474Sroyger selrecord(td, &u->ev_rsel); 550273474Sroyger } 551273474Sroyger } 552273474Sroyger mtx_unlock(&u->ring_prod_mutex); 553273474Sroyger 554273474Sroyger return (mask); 555273474Sroyger} 556273474Sroyger 557273474Sroyger/*------------------ Private Device Attachment Functions --------------------*/ 558273474Sroygerstatic void 559273474Sroygerevtchn_identify(driver_t *driver, device_t parent) 560273474Sroyger{ 561273474Sroyger 562273474Sroyger KASSERT((xen_domain()), 563273474Sroyger ("Trying to attach evtchn device on non Xen domain")); 564273474Sroyger 565273474Sroyger evtchn_dev = BUS_ADD_CHILD(parent, 0, "evtchn", 0); 566273474Sroyger if (evtchn_dev == NULL) 567273474Sroyger panic("unable to attach evtchn user-space device"); 568273474Sroyger} 569273474Sroyger 570273474Sroygerstatic int 571273474Sroygerevtchn_probe(device_t dev) 572273474Sroyger{ 573273474Sroyger 574273474Sroyger device_set_desc(dev, "Xen event channel user-space device"); 575273474Sroyger return (BUS_PROBE_NOWILDCARD); 576273474Sroyger} 577273474Sroyger 578273474Sroygerstatic int 579273474Sroygerevtchn_attach(device_t dev) 580273474Sroyger{ 581273474Sroyger 582273474Sroyger make_dev_credf(MAKEDEV_ETERNAL, &evtchn_devsw, 0, NULL, UID_ROOT, 583273474Sroyger GID_WHEEL, 0600, "xen/evtchn"); 584273474Sroyger return (0); 585273474Sroyger} 586273474Sroyger 587273474Sroyger/*-------------------- Private Device Attachment Data -----------------------*/ 588273474Sroygerstatic device_method_t evtchn_methods[] = { 589273474Sroyger DEVMETHOD(device_identify, evtchn_identify), 590273474Sroyger DEVMETHOD(device_probe, evtchn_probe), 591273474Sroyger DEVMETHOD(device_attach, evtchn_attach), 592273474Sroyger 593273474Sroyger DEVMETHOD_END 594273474Sroyger}; 595273474Sroyger 596273474Sroygerstatic driver_t evtchn_driver = { 597273474Sroyger "evtchn", 598273474Sroyger evtchn_methods, 599273474Sroyger 0, 600273474Sroyger}; 601273474Sroyger 602273474Sroygerdevclass_t evtchn_devclass; 603273474Sroyger 604273474SroygerDRIVER_MODULE(evtchn, xenpv, evtchn_driver, evtchn_devclass, 0, 0); 605273474SroygerMODULE_DEPEND(evtchn, xenpv, 1, 1, 1); 606