1*f7116284SIan Campbell /****************************************************************************** 2*f7116284SIan Campbell * evtchn.c 3*f7116284SIan Campbell * 4*f7116284SIan Campbell * Driver for receiving and demuxing event-channel signals. 5*f7116284SIan Campbell * 6*f7116284SIan Campbell * Copyright (c) 2004-2005, K A Fraser 7*f7116284SIan Campbell * Multi-process extensions Copyright (c) 2004, Steven Smith 8*f7116284SIan Campbell * 9*f7116284SIan Campbell * This program is free software; you can redistribute it and/or 10*f7116284SIan Campbell * modify it under the terms of the GNU General Public License version 2 11*f7116284SIan Campbell * as published by the Free Software Foundation; or, when distributed 12*f7116284SIan Campbell * separately from the Linux kernel or incorporated into other 13*f7116284SIan Campbell * software packages, subject to the following license: 14*f7116284SIan Campbell * 15*f7116284SIan Campbell * Permission is hereby granted, free of charge, to any person obtaining a copy 16*f7116284SIan Campbell * of this source file (the "Software"), to deal in the Software without 17*f7116284SIan Campbell * restriction, including without limitation the rights to use, copy, modify, 18*f7116284SIan Campbell * merge, publish, distribute, sublicense, and/or sell copies of the Software, 19*f7116284SIan Campbell * and to permit persons to whom the Software is furnished to do so, subject to 20*f7116284SIan Campbell * the following conditions: 21*f7116284SIan Campbell * 22*f7116284SIan Campbell * The above copyright notice and this permission notice shall be included in 23*f7116284SIan Campbell * all copies or substantial portions of the Software. 24*f7116284SIan Campbell * 25*f7116284SIan Campbell * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 26*f7116284SIan Campbell * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 27*f7116284SIan Campbell * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 28*f7116284SIan Campbell * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 29*f7116284SIan Campbell * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 30*f7116284SIan Campbell * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 31*f7116284SIan Campbell * IN THE SOFTWARE. 32*f7116284SIan Campbell */ 33*f7116284SIan Campbell 34*f7116284SIan Campbell #include <linux/module.h> 35*f7116284SIan Campbell #include <linux/kernel.h> 36*f7116284SIan Campbell #include <linux/sched.h> 37*f7116284SIan Campbell #include <linux/slab.h> 38*f7116284SIan Campbell #include <linux/string.h> 39*f7116284SIan Campbell #include <linux/errno.h> 40*f7116284SIan Campbell #include <linux/fs.h> 41*f7116284SIan Campbell #include <linux/errno.h> 42*f7116284SIan Campbell #include <linux/miscdevice.h> 43*f7116284SIan Campbell #include <linux/major.h> 44*f7116284SIan Campbell #include <linux/proc_fs.h> 45*f7116284SIan Campbell #include <linux/stat.h> 46*f7116284SIan Campbell #include <linux/poll.h> 47*f7116284SIan Campbell #include <linux/irq.h> 48*f7116284SIan Campbell #include <linux/init.h> 49*f7116284SIan Campbell #include <linux/gfp.h> 50*f7116284SIan Campbell #include <linux/mutex.h> 51*f7116284SIan Campbell #include <linux/cpu.h> 52*f7116284SIan Campbell #include <xen/events.h> 53*f7116284SIan Campbell #include <xen/evtchn.h> 54*f7116284SIan Campbell #include <asm/xen/hypervisor.h> 55*f7116284SIan Campbell 56*f7116284SIan Campbell struct per_user_data { 57*f7116284SIan Campbell /* Notification ring, accessed via /dev/xen/evtchn. */ 58*f7116284SIan Campbell #define EVTCHN_RING_SIZE (PAGE_SIZE / sizeof(evtchn_port_t)) 59*f7116284SIan Campbell #define EVTCHN_RING_MASK(_i) ((_i)&(EVTCHN_RING_SIZE-1)) 60*f7116284SIan Campbell evtchn_port_t *ring; 61*f7116284SIan Campbell unsigned int ring_cons, ring_prod, ring_overflow; 62*f7116284SIan Campbell struct mutex ring_cons_mutex; /* protect against concurrent readers */ 63*f7116284SIan Campbell 64*f7116284SIan Campbell /* Processes wait on this queue when ring is empty. */ 65*f7116284SIan Campbell wait_queue_head_t evtchn_wait; 66*f7116284SIan Campbell struct fasync_struct *evtchn_async_queue; 67*f7116284SIan Campbell const char *name; 68*f7116284SIan Campbell }; 69*f7116284SIan Campbell 70*f7116284SIan Campbell /* Who's bound to each port? */ 71*f7116284SIan Campbell static struct per_user_data *port_user[NR_EVENT_CHANNELS]; 72*f7116284SIan Campbell static DEFINE_SPINLOCK(port_user_lock); 73*f7116284SIan Campbell 74*f7116284SIan Campbell irqreturn_t evtchn_interrupt(int irq, void *data) 75*f7116284SIan Campbell { 76*f7116284SIan Campbell unsigned int port = (unsigned long)data; 77*f7116284SIan Campbell struct per_user_data *u; 78*f7116284SIan Campbell 79*f7116284SIan Campbell spin_lock(&port_user_lock); 80*f7116284SIan Campbell 81*f7116284SIan Campbell u = port_user[port]; 82*f7116284SIan Campbell 83*f7116284SIan Campbell disable_irq_nosync(irq); 84*f7116284SIan Campbell 85*f7116284SIan Campbell if ((u->ring_prod - u->ring_cons) < EVTCHN_RING_SIZE) { 86*f7116284SIan Campbell u->ring[EVTCHN_RING_MASK(u->ring_prod)] = port; 87*f7116284SIan Campbell wmb(); /* Ensure ring contents visible */ 88*f7116284SIan Campbell if (u->ring_cons == u->ring_prod++) { 89*f7116284SIan Campbell wake_up_interruptible(&u->evtchn_wait); 90*f7116284SIan Campbell kill_fasync(&u->evtchn_async_queue, 91*f7116284SIan Campbell SIGIO, POLL_IN); 92*f7116284SIan Campbell } 93*f7116284SIan Campbell } else { 94*f7116284SIan Campbell u->ring_overflow = 1; 95*f7116284SIan Campbell } 96*f7116284SIan Campbell 97*f7116284SIan Campbell spin_unlock(&port_user_lock); 98*f7116284SIan Campbell 99*f7116284SIan Campbell return IRQ_HANDLED; 100*f7116284SIan Campbell } 101*f7116284SIan Campbell 102*f7116284SIan Campbell static ssize_t evtchn_read(struct file *file, char __user *buf, 103*f7116284SIan Campbell size_t count, loff_t *ppos) 104*f7116284SIan Campbell { 105*f7116284SIan Campbell int rc; 106*f7116284SIan Campbell unsigned int c, p, bytes1 = 0, bytes2 = 0; 107*f7116284SIan Campbell struct per_user_data *u = file->private_data; 108*f7116284SIan Campbell 109*f7116284SIan Campbell /* Whole number of ports. */ 110*f7116284SIan Campbell count &= ~(sizeof(evtchn_port_t)-1); 111*f7116284SIan Campbell 112*f7116284SIan Campbell if (count == 0) 113*f7116284SIan Campbell return 0; 114*f7116284SIan Campbell 115*f7116284SIan Campbell if (count > PAGE_SIZE) 116*f7116284SIan Campbell count = PAGE_SIZE; 117*f7116284SIan Campbell 118*f7116284SIan Campbell for (;;) { 119*f7116284SIan Campbell mutex_lock(&u->ring_cons_mutex); 120*f7116284SIan Campbell 121*f7116284SIan Campbell rc = -EFBIG; 122*f7116284SIan Campbell if (u->ring_overflow) 123*f7116284SIan Campbell goto unlock_out; 124*f7116284SIan Campbell 125*f7116284SIan Campbell c = u->ring_cons; 126*f7116284SIan Campbell p = u->ring_prod; 127*f7116284SIan Campbell if (c != p) 128*f7116284SIan Campbell break; 129*f7116284SIan Campbell 130*f7116284SIan Campbell mutex_unlock(&u->ring_cons_mutex); 131*f7116284SIan Campbell 132*f7116284SIan Campbell if (file->f_flags & O_NONBLOCK) 133*f7116284SIan Campbell return -EAGAIN; 134*f7116284SIan Campbell 135*f7116284SIan Campbell rc = wait_event_interruptible(u->evtchn_wait, 136*f7116284SIan Campbell u->ring_cons != u->ring_prod); 137*f7116284SIan Campbell if (rc) 138*f7116284SIan Campbell return rc; 139*f7116284SIan Campbell } 140*f7116284SIan Campbell 141*f7116284SIan Campbell /* Byte lengths of two chunks. Chunk split (if any) is at ring wrap. */ 142*f7116284SIan Campbell if (((c ^ p) & EVTCHN_RING_SIZE) != 0) { 143*f7116284SIan Campbell bytes1 = (EVTCHN_RING_SIZE - EVTCHN_RING_MASK(c)) * 144*f7116284SIan Campbell sizeof(evtchn_port_t); 145*f7116284SIan Campbell bytes2 = EVTCHN_RING_MASK(p) * sizeof(evtchn_port_t); 146*f7116284SIan Campbell } else { 147*f7116284SIan Campbell bytes1 = (p - c) * sizeof(evtchn_port_t); 148*f7116284SIan Campbell bytes2 = 0; 149*f7116284SIan Campbell } 150*f7116284SIan Campbell 151*f7116284SIan Campbell /* Truncate chunks according to caller's maximum byte count. */ 152*f7116284SIan Campbell if (bytes1 > count) { 153*f7116284SIan Campbell bytes1 = count; 154*f7116284SIan Campbell bytes2 = 0; 155*f7116284SIan Campbell } else if ((bytes1 + bytes2) > count) { 156*f7116284SIan Campbell bytes2 = count - bytes1; 157*f7116284SIan Campbell } 158*f7116284SIan Campbell 159*f7116284SIan Campbell rc = -EFAULT; 160*f7116284SIan Campbell rmb(); /* Ensure that we see the port before we copy it. */ 161*f7116284SIan Campbell if (copy_to_user(buf, &u->ring[EVTCHN_RING_MASK(c)], bytes1) || 162*f7116284SIan Campbell ((bytes2 != 0) && 163*f7116284SIan Campbell copy_to_user(&buf[bytes1], &u->ring[0], bytes2))) 164*f7116284SIan Campbell goto unlock_out; 165*f7116284SIan Campbell 166*f7116284SIan Campbell u->ring_cons += (bytes1 + bytes2) / sizeof(evtchn_port_t); 167*f7116284SIan Campbell rc = bytes1 + bytes2; 168*f7116284SIan Campbell 169*f7116284SIan Campbell unlock_out: 170*f7116284SIan Campbell mutex_unlock(&u->ring_cons_mutex); 171*f7116284SIan Campbell return rc; 172*f7116284SIan Campbell } 173*f7116284SIan Campbell 174*f7116284SIan Campbell static ssize_t evtchn_write(struct file *file, const char __user *buf, 175*f7116284SIan Campbell size_t count, loff_t *ppos) 176*f7116284SIan Campbell { 177*f7116284SIan Campbell int rc, i; 178*f7116284SIan Campbell evtchn_port_t *kbuf = (evtchn_port_t *)__get_free_page(GFP_KERNEL); 179*f7116284SIan Campbell struct per_user_data *u = file->private_data; 180*f7116284SIan Campbell 181*f7116284SIan Campbell if (kbuf == NULL) 182*f7116284SIan Campbell return -ENOMEM; 183*f7116284SIan Campbell 184*f7116284SIan Campbell /* Whole number of ports. */ 185*f7116284SIan Campbell count &= ~(sizeof(evtchn_port_t)-1); 186*f7116284SIan Campbell 187*f7116284SIan Campbell rc = 0; 188*f7116284SIan Campbell if (count == 0) 189*f7116284SIan Campbell goto out; 190*f7116284SIan Campbell 191*f7116284SIan Campbell if (count > PAGE_SIZE) 192*f7116284SIan Campbell count = PAGE_SIZE; 193*f7116284SIan Campbell 194*f7116284SIan Campbell rc = -EFAULT; 195*f7116284SIan Campbell if (copy_from_user(kbuf, buf, count) != 0) 196*f7116284SIan Campbell goto out; 197*f7116284SIan Campbell 198*f7116284SIan Campbell spin_lock_irq(&port_user_lock); 199*f7116284SIan Campbell for (i = 0; i < (count/sizeof(evtchn_port_t)); i++) 200*f7116284SIan Campbell if ((kbuf[i] < NR_EVENT_CHANNELS) && (port_user[kbuf[i]] == u)) 201*f7116284SIan Campbell enable_irq(irq_from_evtchn(kbuf[i])); 202*f7116284SIan Campbell spin_unlock_irq(&port_user_lock); 203*f7116284SIan Campbell 204*f7116284SIan Campbell rc = count; 205*f7116284SIan Campbell 206*f7116284SIan Campbell out: 207*f7116284SIan Campbell free_page((unsigned long)kbuf); 208*f7116284SIan Campbell return rc; 209*f7116284SIan Campbell } 210*f7116284SIan Campbell 211*f7116284SIan Campbell static int evtchn_bind_to_user(struct per_user_data *u, int port) 212*f7116284SIan Campbell { 213*f7116284SIan Campbell int irq; 214*f7116284SIan Campbell int rc = 0; 215*f7116284SIan Campbell 216*f7116284SIan Campbell spin_lock_irq(&port_user_lock); 217*f7116284SIan Campbell 218*f7116284SIan Campbell BUG_ON(port_user[port] != NULL); 219*f7116284SIan Campbell 220*f7116284SIan Campbell irq = bind_evtchn_to_irqhandler(port, evtchn_interrupt, IRQF_DISABLED, 221*f7116284SIan Campbell u->name, (void *)(unsigned long)port); 222*f7116284SIan Campbell if (rc < 0) 223*f7116284SIan Campbell goto fail; 224*f7116284SIan Campbell 225*f7116284SIan Campbell port_user[port] = u; 226*f7116284SIan Campbell 227*f7116284SIan Campbell fail: 228*f7116284SIan Campbell spin_unlock_irq(&port_user_lock); 229*f7116284SIan Campbell return rc; 230*f7116284SIan Campbell } 231*f7116284SIan Campbell 232*f7116284SIan Campbell static void evtchn_unbind_from_user(struct per_user_data *u, int port) 233*f7116284SIan Campbell { 234*f7116284SIan Campbell int irq = irq_from_evtchn(port); 235*f7116284SIan Campbell 236*f7116284SIan Campbell unbind_from_irqhandler(irq, (void *)(unsigned long)port); 237*f7116284SIan Campbell port_user[port] = NULL; 238*f7116284SIan Campbell } 239*f7116284SIan Campbell 240*f7116284SIan Campbell static long evtchn_ioctl(struct file *file, 241*f7116284SIan Campbell unsigned int cmd, unsigned long arg) 242*f7116284SIan Campbell { 243*f7116284SIan Campbell int rc; 244*f7116284SIan Campbell struct per_user_data *u = file->private_data; 245*f7116284SIan Campbell void __user *uarg = (void __user *) arg; 246*f7116284SIan Campbell 247*f7116284SIan Campbell switch (cmd) { 248*f7116284SIan Campbell case IOCTL_EVTCHN_BIND_VIRQ: { 249*f7116284SIan Campbell struct ioctl_evtchn_bind_virq bind; 250*f7116284SIan Campbell struct evtchn_bind_virq bind_virq; 251*f7116284SIan Campbell 252*f7116284SIan Campbell rc = -EFAULT; 253*f7116284SIan Campbell if (copy_from_user(&bind, uarg, sizeof(bind))) 254*f7116284SIan Campbell break; 255*f7116284SIan Campbell 256*f7116284SIan Campbell bind_virq.virq = bind.virq; 257*f7116284SIan Campbell bind_virq.vcpu = 0; 258*f7116284SIan Campbell rc = HYPERVISOR_event_channel_op(EVTCHNOP_bind_virq, 259*f7116284SIan Campbell &bind_virq); 260*f7116284SIan Campbell if (rc != 0) 261*f7116284SIan Campbell break; 262*f7116284SIan Campbell 263*f7116284SIan Campbell rc = evtchn_bind_to_user(u, bind_virq.port); 264*f7116284SIan Campbell if (rc == 0) 265*f7116284SIan Campbell rc = bind_virq.port; 266*f7116284SIan Campbell break; 267*f7116284SIan Campbell } 268*f7116284SIan Campbell 269*f7116284SIan Campbell case IOCTL_EVTCHN_BIND_INTERDOMAIN: { 270*f7116284SIan Campbell struct ioctl_evtchn_bind_interdomain bind; 271*f7116284SIan Campbell struct evtchn_bind_interdomain bind_interdomain; 272*f7116284SIan Campbell 273*f7116284SIan Campbell rc = -EFAULT; 274*f7116284SIan Campbell if (copy_from_user(&bind, uarg, sizeof(bind))) 275*f7116284SIan Campbell break; 276*f7116284SIan Campbell 277*f7116284SIan Campbell bind_interdomain.remote_dom = bind.remote_domain; 278*f7116284SIan Campbell bind_interdomain.remote_port = bind.remote_port; 279*f7116284SIan Campbell rc = HYPERVISOR_event_channel_op(EVTCHNOP_bind_interdomain, 280*f7116284SIan Campbell &bind_interdomain); 281*f7116284SIan Campbell if (rc != 0) 282*f7116284SIan Campbell break; 283*f7116284SIan Campbell 284*f7116284SIan Campbell rc = evtchn_bind_to_user(u, bind_interdomain.local_port); 285*f7116284SIan Campbell if (rc == 0) 286*f7116284SIan Campbell rc = bind_interdomain.local_port; 287*f7116284SIan Campbell break; 288*f7116284SIan Campbell } 289*f7116284SIan Campbell 290*f7116284SIan Campbell case IOCTL_EVTCHN_BIND_UNBOUND_PORT: { 291*f7116284SIan Campbell struct ioctl_evtchn_bind_unbound_port bind; 292*f7116284SIan Campbell struct evtchn_alloc_unbound alloc_unbound; 293*f7116284SIan Campbell 294*f7116284SIan Campbell rc = -EFAULT; 295*f7116284SIan Campbell if (copy_from_user(&bind, uarg, sizeof(bind))) 296*f7116284SIan Campbell break; 297*f7116284SIan Campbell 298*f7116284SIan Campbell alloc_unbound.dom = DOMID_SELF; 299*f7116284SIan Campbell alloc_unbound.remote_dom = bind.remote_domain; 300*f7116284SIan Campbell rc = HYPERVISOR_event_channel_op(EVTCHNOP_alloc_unbound, 301*f7116284SIan Campbell &alloc_unbound); 302*f7116284SIan Campbell if (rc != 0) 303*f7116284SIan Campbell break; 304*f7116284SIan Campbell 305*f7116284SIan Campbell rc = evtchn_bind_to_user(u, alloc_unbound.port); 306*f7116284SIan Campbell if (rc == 0) 307*f7116284SIan Campbell rc = alloc_unbound.port; 308*f7116284SIan Campbell break; 309*f7116284SIan Campbell } 310*f7116284SIan Campbell 311*f7116284SIan Campbell case IOCTL_EVTCHN_UNBIND: { 312*f7116284SIan Campbell struct ioctl_evtchn_unbind unbind; 313*f7116284SIan Campbell 314*f7116284SIan Campbell rc = -EFAULT; 315*f7116284SIan Campbell if (copy_from_user(&unbind, uarg, sizeof(unbind))) 316*f7116284SIan Campbell break; 317*f7116284SIan Campbell 318*f7116284SIan Campbell rc = -EINVAL; 319*f7116284SIan Campbell if (unbind.port >= NR_EVENT_CHANNELS) 320*f7116284SIan Campbell break; 321*f7116284SIan Campbell 322*f7116284SIan Campbell spin_lock_irq(&port_user_lock); 323*f7116284SIan Campbell 324*f7116284SIan Campbell rc = -ENOTCONN; 325*f7116284SIan Campbell if (port_user[unbind.port] != u) { 326*f7116284SIan Campbell spin_unlock_irq(&port_user_lock); 327*f7116284SIan Campbell break; 328*f7116284SIan Campbell } 329*f7116284SIan Campbell 330*f7116284SIan Campbell evtchn_unbind_from_user(u, unbind.port); 331*f7116284SIan Campbell 332*f7116284SIan Campbell spin_unlock_irq(&port_user_lock); 333*f7116284SIan Campbell 334*f7116284SIan Campbell rc = 0; 335*f7116284SIan Campbell break; 336*f7116284SIan Campbell } 337*f7116284SIan Campbell 338*f7116284SIan Campbell case IOCTL_EVTCHN_NOTIFY: { 339*f7116284SIan Campbell struct ioctl_evtchn_notify notify; 340*f7116284SIan Campbell 341*f7116284SIan Campbell rc = -EFAULT; 342*f7116284SIan Campbell if (copy_from_user(¬ify, uarg, sizeof(notify))) 343*f7116284SIan Campbell break; 344*f7116284SIan Campbell 345*f7116284SIan Campbell if (notify.port >= NR_EVENT_CHANNELS) { 346*f7116284SIan Campbell rc = -EINVAL; 347*f7116284SIan Campbell } else if (port_user[notify.port] != u) { 348*f7116284SIan Campbell rc = -ENOTCONN; 349*f7116284SIan Campbell } else { 350*f7116284SIan Campbell notify_remote_via_evtchn(notify.port); 351*f7116284SIan Campbell rc = 0; 352*f7116284SIan Campbell } 353*f7116284SIan Campbell break; 354*f7116284SIan Campbell } 355*f7116284SIan Campbell 356*f7116284SIan Campbell case IOCTL_EVTCHN_RESET: { 357*f7116284SIan Campbell /* Initialise the ring to empty. Clear errors. */ 358*f7116284SIan Campbell mutex_lock(&u->ring_cons_mutex); 359*f7116284SIan Campbell spin_lock_irq(&port_user_lock); 360*f7116284SIan Campbell u->ring_cons = u->ring_prod = u->ring_overflow = 0; 361*f7116284SIan Campbell spin_unlock_irq(&port_user_lock); 362*f7116284SIan Campbell mutex_unlock(&u->ring_cons_mutex); 363*f7116284SIan Campbell rc = 0; 364*f7116284SIan Campbell break; 365*f7116284SIan Campbell } 366*f7116284SIan Campbell 367*f7116284SIan Campbell default: 368*f7116284SIan Campbell rc = -ENOSYS; 369*f7116284SIan Campbell break; 370*f7116284SIan Campbell } 371*f7116284SIan Campbell 372*f7116284SIan Campbell return rc; 373*f7116284SIan Campbell } 374*f7116284SIan Campbell 375*f7116284SIan Campbell static unsigned int evtchn_poll(struct file *file, poll_table *wait) 376*f7116284SIan Campbell { 377*f7116284SIan Campbell unsigned int mask = POLLOUT | POLLWRNORM; 378*f7116284SIan Campbell struct per_user_data *u = file->private_data; 379*f7116284SIan Campbell 380*f7116284SIan Campbell poll_wait(file, &u->evtchn_wait, wait); 381*f7116284SIan Campbell if (u->ring_cons != u->ring_prod) 382*f7116284SIan Campbell mask |= POLLIN | POLLRDNORM; 383*f7116284SIan Campbell if (u->ring_overflow) 384*f7116284SIan Campbell mask = POLLERR; 385*f7116284SIan Campbell return mask; 386*f7116284SIan Campbell } 387*f7116284SIan Campbell 388*f7116284SIan Campbell static int evtchn_fasync(int fd, struct file *filp, int on) 389*f7116284SIan Campbell { 390*f7116284SIan Campbell struct per_user_data *u = filp->private_data; 391*f7116284SIan Campbell return fasync_helper(fd, filp, on, &u->evtchn_async_queue); 392*f7116284SIan Campbell } 393*f7116284SIan Campbell 394*f7116284SIan Campbell static int evtchn_open(struct inode *inode, struct file *filp) 395*f7116284SIan Campbell { 396*f7116284SIan Campbell struct per_user_data *u; 397*f7116284SIan Campbell 398*f7116284SIan Campbell u = kzalloc(sizeof(*u), GFP_KERNEL); 399*f7116284SIan Campbell if (u == NULL) 400*f7116284SIan Campbell return -ENOMEM; 401*f7116284SIan Campbell 402*f7116284SIan Campbell u->name = kasprintf(GFP_KERNEL, "evtchn:%s", current->comm); 403*f7116284SIan Campbell if (u->name == NULL) { 404*f7116284SIan Campbell kfree(u); 405*f7116284SIan Campbell return -ENOMEM; 406*f7116284SIan Campbell } 407*f7116284SIan Campbell 408*f7116284SIan Campbell init_waitqueue_head(&u->evtchn_wait); 409*f7116284SIan Campbell 410*f7116284SIan Campbell u->ring = (evtchn_port_t *)__get_free_page(GFP_KERNEL); 411*f7116284SIan Campbell if (u->ring == NULL) { 412*f7116284SIan Campbell kfree(u->name); 413*f7116284SIan Campbell kfree(u); 414*f7116284SIan Campbell return -ENOMEM; 415*f7116284SIan Campbell } 416*f7116284SIan Campbell 417*f7116284SIan Campbell mutex_init(&u->ring_cons_mutex); 418*f7116284SIan Campbell 419*f7116284SIan Campbell filp->private_data = u; 420*f7116284SIan Campbell 421*f7116284SIan Campbell return 0; 422*f7116284SIan Campbell } 423*f7116284SIan Campbell 424*f7116284SIan Campbell static int evtchn_release(struct inode *inode, struct file *filp) 425*f7116284SIan Campbell { 426*f7116284SIan Campbell int i; 427*f7116284SIan Campbell struct per_user_data *u = filp->private_data; 428*f7116284SIan Campbell 429*f7116284SIan Campbell spin_lock_irq(&port_user_lock); 430*f7116284SIan Campbell 431*f7116284SIan Campbell free_page((unsigned long)u->ring); 432*f7116284SIan Campbell 433*f7116284SIan Campbell for (i = 0; i < NR_EVENT_CHANNELS; i++) { 434*f7116284SIan Campbell if (port_user[i] != u) 435*f7116284SIan Campbell continue; 436*f7116284SIan Campbell 437*f7116284SIan Campbell evtchn_unbind_from_user(port_user[i], i); 438*f7116284SIan Campbell } 439*f7116284SIan Campbell 440*f7116284SIan Campbell spin_unlock_irq(&port_user_lock); 441*f7116284SIan Campbell 442*f7116284SIan Campbell kfree(u->name); 443*f7116284SIan Campbell kfree(u); 444*f7116284SIan Campbell 445*f7116284SIan Campbell return 0; 446*f7116284SIan Campbell } 447*f7116284SIan Campbell 448*f7116284SIan Campbell static const struct file_operations evtchn_fops = { 449*f7116284SIan Campbell .owner = THIS_MODULE, 450*f7116284SIan Campbell .read = evtchn_read, 451*f7116284SIan Campbell .write = evtchn_write, 452*f7116284SIan Campbell .unlocked_ioctl = evtchn_ioctl, 453*f7116284SIan Campbell .poll = evtchn_poll, 454*f7116284SIan Campbell .fasync = evtchn_fasync, 455*f7116284SIan Campbell .open = evtchn_open, 456*f7116284SIan Campbell .release = evtchn_release, 457*f7116284SIan Campbell }; 458*f7116284SIan Campbell 459*f7116284SIan Campbell static struct miscdevice evtchn_miscdev = { 460*f7116284SIan Campbell .minor = MISC_DYNAMIC_MINOR, 461*f7116284SIan Campbell .name = "evtchn", 462*f7116284SIan Campbell .fops = &evtchn_fops, 463*f7116284SIan Campbell }; 464*f7116284SIan Campbell static int __init evtchn_init(void) 465*f7116284SIan Campbell { 466*f7116284SIan Campbell int err; 467*f7116284SIan Campbell 468*f7116284SIan Campbell if (!xen_domain()) 469*f7116284SIan Campbell return -ENODEV; 470*f7116284SIan Campbell 471*f7116284SIan Campbell spin_lock_init(&port_user_lock); 472*f7116284SIan Campbell memset(port_user, 0, sizeof(port_user)); 473*f7116284SIan Campbell 474*f7116284SIan Campbell /* Create '/dev/misc/evtchn'. */ 475*f7116284SIan Campbell err = misc_register(&evtchn_miscdev); 476*f7116284SIan Campbell if (err != 0) { 477*f7116284SIan Campbell printk(KERN_ALERT "Could not register /dev/misc/evtchn\n"); 478*f7116284SIan Campbell return err; 479*f7116284SIan Campbell } 480*f7116284SIan Campbell 481*f7116284SIan Campbell printk(KERN_INFO "Event-channel device installed.\n"); 482*f7116284SIan Campbell 483*f7116284SIan Campbell return 0; 484*f7116284SIan Campbell } 485*f7116284SIan Campbell 486*f7116284SIan Campbell static void __exit evtchn_cleanup(void) 487*f7116284SIan Campbell { 488*f7116284SIan Campbell misc_deregister(&evtchn_miscdev); 489*f7116284SIan Campbell } 490*f7116284SIan Campbell 491*f7116284SIan Campbell module_init(evtchn_init); 492*f7116284SIan Campbell module_exit(evtchn_cleanup); 493*f7116284SIan Campbell 494*f7116284SIan Campbell MODULE_LICENSE("GPL"); 495