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