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 34*283c0972SJoe Perches #define pr_fmt(fmt) "xen:" KBUILD_MODNAME ": " fmt 35*283c0972SJoe Perches 36f7116284SIan Campbell #include <linux/module.h> 37f7116284SIan Campbell #include <linux/kernel.h> 38f7116284SIan Campbell #include <linux/sched.h> 39f7116284SIan Campbell #include <linux/slab.h> 40f7116284SIan Campbell #include <linux/string.h> 41f7116284SIan Campbell #include <linux/errno.h> 42f7116284SIan Campbell #include <linux/fs.h> 43f7116284SIan Campbell #include <linux/miscdevice.h> 44f7116284SIan Campbell #include <linux/major.h> 45f7116284SIan Campbell #include <linux/proc_fs.h> 46f7116284SIan Campbell #include <linux/stat.h> 47f7116284SIan Campbell #include <linux/poll.h> 48f7116284SIan Campbell #include <linux/irq.h> 49f7116284SIan Campbell #include <linux/init.h> 50f7116284SIan Campbell #include <linux/mutex.h> 51f7116284SIan Campbell #include <linux/cpu.h> 521ccbf534SJeremy Fitzhardinge 531ccbf534SJeremy Fitzhardinge #include <xen/xen.h> 54f7116284SIan Campbell #include <xen/events.h> 55f7116284SIan Campbell #include <xen/evtchn.h> 56f7116284SIan Campbell #include <asm/xen/hypervisor.h> 57f7116284SIan Campbell 58f7116284SIan Campbell struct per_user_data { 590a4666b5SJeremy Fitzhardinge struct mutex bind_mutex; /* serialize bind/unbind operations */ 600a4666b5SJeremy Fitzhardinge 61f7116284SIan Campbell /* Notification ring, accessed via /dev/xen/evtchn. */ 62f7116284SIan Campbell #define EVTCHN_RING_SIZE (PAGE_SIZE / sizeof(evtchn_port_t)) 63f7116284SIan Campbell #define EVTCHN_RING_MASK(_i) ((_i)&(EVTCHN_RING_SIZE-1)) 64f7116284SIan Campbell evtchn_port_t *ring; 65f7116284SIan Campbell unsigned int ring_cons, ring_prod, ring_overflow; 66f7116284SIan Campbell struct mutex ring_cons_mutex; /* protect against concurrent readers */ 67f7116284SIan Campbell 68f7116284SIan Campbell /* Processes wait on this queue when ring is empty. */ 69f7116284SIan Campbell wait_queue_head_t evtchn_wait; 70f7116284SIan Campbell struct fasync_struct *evtchn_async_queue; 71f7116284SIan Campbell const char *name; 72f7116284SIan Campbell }; 73f7116284SIan Campbell 74e3cc067bSJeremy Fitzhardinge /* 75e3cc067bSJeremy Fitzhardinge * Who's bound to each port? This is logically an array of struct 76e3cc067bSJeremy Fitzhardinge * per_user_data *, but we encode the current enabled-state in bit 0. 77e3cc067bSJeremy Fitzhardinge */ 7893afe0b7SJeremy Fitzhardinge static unsigned long *port_user; 790a4666b5SJeremy Fitzhardinge static DEFINE_SPINLOCK(port_user_lock); /* protects port_user[] and ring_prod */ 80f7116284SIan Campbell 81e3cc067bSJeremy Fitzhardinge static inline struct per_user_data *get_port_user(unsigned port) 82e3cc067bSJeremy Fitzhardinge { 83e3cc067bSJeremy Fitzhardinge return (struct per_user_data *)(port_user[port] & ~1); 84e3cc067bSJeremy Fitzhardinge } 85e3cc067bSJeremy Fitzhardinge 86e3cc067bSJeremy Fitzhardinge static inline void set_port_user(unsigned port, struct per_user_data *u) 87e3cc067bSJeremy Fitzhardinge { 88e3cc067bSJeremy Fitzhardinge port_user[port] = (unsigned long)u; 89e3cc067bSJeremy Fitzhardinge } 90e3cc067bSJeremy Fitzhardinge 91e3cc067bSJeremy Fitzhardinge static inline bool get_port_enabled(unsigned port) 92e3cc067bSJeremy Fitzhardinge { 93e3cc067bSJeremy Fitzhardinge return port_user[port] & 1; 94e3cc067bSJeremy Fitzhardinge } 95e3cc067bSJeremy Fitzhardinge 96e3cc067bSJeremy Fitzhardinge static inline void set_port_enabled(unsigned port, bool enabled) 97e3cc067bSJeremy Fitzhardinge { 98e3cc067bSJeremy Fitzhardinge if (enabled) 99e3cc067bSJeremy Fitzhardinge port_user[port] |= 1; 100e3cc067bSJeremy Fitzhardinge else 101e3cc067bSJeremy Fitzhardinge port_user[port] &= ~1; 102e3cc067bSJeremy Fitzhardinge } 103e3cc067bSJeremy Fitzhardinge 10470697d54SJeremy Fitzhardinge static irqreturn_t evtchn_interrupt(int irq, void *data) 105f7116284SIan Campbell { 106f7116284SIan Campbell unsigned int port = (unsigned long)data; 107f7116284SIan Campbell struct per_user_data *u; 108f7116284SIan Campbell 109f7116284SIan Campbell spin_lock(&port_user_lock); 110f7116284SIan Campbell 111e3cc067bSJeremy Fitzhardinge u = get_port_user(port); 112e3cc067bSJeremy Fitzhardinge 1130edce91dSJeremy Fitzhardinge WARN(!get_port_enabled(port), 114e3cc067bSJeremy Fitzhardinge "Interrupt for port %d, but apparently not enabled; per-user %p\n", 1150edce91dSJeremy Fitzhardinge port, u); 116f7116284SIan Campbell 117f7116284SIan Campbell disable_irq_nosync(irq); 118e3cc067bSJeremy Fitzhardinge set_port_enabled(port, false); 119f7116284SIan Campbell 120f7116284SIan Campbell if ((u->ring_prod - u->ring_cons) < EVTCHN_RING_SIZE) { 121f7116284SIan Campbell u->ring[EVTCHN_RING_MASK(u->ring_prod)] = port; 122f7116284SIan Campbell wmb(); /* Ensure ring contents visible */ 123f7116284SIan Campbell if (u->ring_cons == u->ring_prod++) { 124f7116284SIan Campbell wake_up_interruptible(&u->evtchn_wait); 125f7116284SIan Campbell kill_fasync(&u->evtchn_async_queue, 126f7116284SIan Campbell SIGIO, POLL_IN); 127f7116284SIan Campbell } 128e3cc067bSJeremy Fitzhardinge } else 129f7116284SIan Campbell u->ring_overflow = 1; 130f7116284SIan Campbell 131f7116284SIan Campbell spin_unlock(&port_user_lock); 132f7116284SIan Campbell 133f7116284SIan Campbell return IRQ_HANDLED; 134f7116284SIan Campbell } 135f7116284SIan Campbell 136f7116284SIan Campbell static ssize_t evtchn_read(struct file *file, char __user *buf, 137f7116284SIan Campbell size_t count, loff_t *ppos) 138f7116284SIan Campbell { 139f7116284SIan Campbell int rc; 140f7116284SIan Campbell unsigned int c, p, bytes1 = 0, bytes2 = 0; 141f7116284SIan Campbell struct per_user_data *u = file->private_data; 142f7116284SIan Campbell 143f7116284SIan Campbell /* Whole number of ports. */ 144f7116284SIan Campbell count &= ~(sizeof(evtchn_port_t)-1); 145f7116284SIan Campbell 146f7116284SIan Campbell if (count == 0) 147f7116284SIan Campbell return 0; 148f7116284SIan Campbell 149f7116284SIan Campbell if (count > PAGE_SIZE) 150f7116284SIan Campbell count = PAGE_SIZE; 151f7116284SIan Campbell 152f7116284SIan Campbell for (;;) { 153f7116284SIan Campbell mutex_lock(&u->ring_cons_mutex); 154f7116284SIan Campbell 155f7116284SIan Campbell rc = -EFBIG; 156f7116284SIan Campbell if (u->ring_overflow) 157f7116284SIan Campbell goto unlock_out; 158f7116284SIan Campbell 159f7116284SIan Campbell c = u->ring_cons; 160f7116284SIan Campbell p = u->ring_prod; 161f7116284SIan Campbell if (c != p) 162f7116284SIan Campbell break; 163f7116284SIan Campbell 164f7116284SIan Campbell mutex_unlock(&u->ring_cons_mutex); 165f7116284SIan Campbell 166f7116284SIan Campbell if (file->f_flags & O_NONBLOCK) 167f7116284SIan Campbell return -EAGAIN; 168f7116284SIan Campbell 169f7116284SIan Campbell rc = wait_event_interruptible(u->evtchn_wait, 170f7116284SIan Campbell u->ring_cons != u->ring_prod); 171f7116284SIan Campbell if (rc) 172f7116284SIan Campbell return rc; 173f7116284SIan Campbell } 174f7116284SIan Campbell 175f7116284SIan Campbell /* Byte lengths of two chunks. Chunk split (if any) is at ring wrap. */ 176f7116284SIan Campbell if (((c ^ p) & EVTCHN_RING_SIZE) != 0) { 177f7116284SIan Campbell bytes1 = (EVTCHN_RING_SIZE - EVTCHN_RING_MASK(c)) * 178f7116284SIan Campbell sizeof(evtchn_port_t); 179f7116284SIan Campbell bytes2 = EVTCHN_RING_MASK(p) * sizeof(evtchn_port_t); 180f7116284SIan Campbell } else { 181f7116284SIan Campbell bytes1 = (p - c) * sizeof(evtchn_port_t); 182f7116284SIan Campbell bytes2 = 0; 183f7116284SIan Campbell } 184f7116284SIan Campbell 185f7116284SIan Campbell /* Truncate chunks according to caller's maximum byte count. */ 186f7116284SIan Campbell if (bytes1 > count) { 187f7116284SIan Campbell bytes1 = count; 188f7116284SIan Campbell bytes2 = 0; 189f7116284SIan Campbell } else if ((bytes1 + bytes2) > count) { 190f7116284SIan Campbell bytes2 = count - bytes1; 191f7116284SIan Campbell } 192f7116284SIan Campbell 193f7116284SIan Campbell rc = -EFAULT; 194f7116284SIan Campbell rmb(); /* Ensure that we see the port before we copy it. */ 195f7116284SIan Campbell if (copy_to_user(buf, &u->ring[EVTCHN_RING_MASK(c)], bytes1) || 196f7116284SIan Campbell ((bytes2 != 0) && 197f7116284SIan Campbell copy_to_user(&buf[bytes1], &u->ring[0], bytes2))) 198f7116284SIan Campbell goto unlock_out; 199f7116284SIan Campbell 200f7116284SIan Campbell u->ring_cons += (bytes1 + bytes2) / sizeof(evtchn_port_t); 201f7116284SIan Campbell rc = bytes1 + bytes2; 202f7116284SIan Campbell 203f7116284SIan Campbell unlock_out: 204f7116284SIan Campbell mutex_unlock(&u->ring_cons_mutex); 205f7116284SIan Campbell return rc; 206f7116284SIan Campbell } 207f7116284SIan Campbell 208f7116284SIan Campbell static ssize_t evtchn_write(struct file *file, const char __user *buf, 209f7116284SIan Campbell size_t count, loff_t *ppos) 210f7116284SIan Campbell { 211f7116284SIan Campbell int rc, i; 212f7116284SIan Campbell evtchn_port_t *kbuf = (evtchn_port_t *)__get_free_page(GFP_KERNEL); 213f7116284SIan Campbell struct per_user_data *u = file->private_data; 214f7116284SIan Campbell 215f7116284SIan Campbell if (kbuf == NULL) 216f7116284SIan Campbell return -ENOMEM; 217f7116284SIan Campbell 218f7116284SIan Campbell /* Whole number of ports. */ 219f7116284SIan Campbell count &= ~(sizeof(evtchn_port_t)-1); 220f7116284SIan Campbell 221f7116284SIan Campbell rc = 0; 222f7116284SIan Campbell if (count == 0) 223f7116284SIan Campbell goto out; 224f7116284SIan Campbell 225f7116284SIan Campbell if (count > PAGE_SIZE) 226f7116284SIan Campbell count = PAGE_SIZE; 227f7116284SIan Campbell 228f7116284SIan Campbell rc = -EFAULT; 229f7116284SIan Campbell if (copy_from_user(kbuf, buf, count) != 0) 230f7116284SIan Campbell goto out; 231f7116284SIan Campbell 232f7116284SIan Campbell spin_lock_irq(&port_user_lock); 233e3cc067bSJeremy Fitzhardinge 234e3cc067bSJeremy Fitzhardinge for (i = 0; i < (count/sizeof(evtchn_port_t)); i++) { 235e3cc067bSJeremy Fitzhardinge unsigned port = kbuf[i]; 236e3cc067bSJeremy Fitzhardinge 237e3cc067bSJeremy Fitzhardinge if (port < NR_EVENT_CHANNELS && 238e3cc067bSJeremy Fitzhardinge get_port_user(port) == u && 239e3cc067bSJeremy Fitzhardinge !get_port_enabled(port)) { 240e3cc067bSJeremy Fitzhardinge set_port_enabled(port, true); 241e3cc067bSJeremy Fitzhardinge enable_irq(irq_from_evtchn(port)); 242e3cc067bSJeremy Fitzhardinge } 243e3cc067bSJeremy Fitzhardinge } 244e3cc067bSJeremy Fitzhardinge 245f7116284SIan Campbell spin_unlock_irq(&port_user_lock); 246f7116284SIan Campbell 247f7116284SIan Campbell rc = count; 248f7116284SIan Campbell 249f7116284SIan Campbell out: 250f7116284SIan Campbell free_page((unsigned long)kbuf); 251f7116284SIan Campbell return rc; 252f7116284SIan Campbell } 253f7116284SIan Campbell 254f7116284SIan Campbell static int evtchn_bind_to_user(struct per_user_data *u, int port) 255f7116284SIan Campbell { 256f7116284SIan Campbell int rc = 0; 257f7116284SIan Campbell 2580a4666b5SJeremy Fitzhardinge /* 2590a4666b5SJeremy Fitzhardinge * Ports are never reused, so every caller should pass in a 2600a4666b5SJeremy Fitzhardinge * unique port. 2610a4666b5SJeremy Fitzhardinge * 2620a4666b5SJeremy Fitzhardinge * (Locking not necessary because we haven't registered the 2630a4666b5SJeremy Fitzhardinge * interrupt handler yet, and our caller has already 2640a4666b5SJeremy Fitzhardinge * serialized bind operations.) 2650a4666b5SJeremy Fitzhardinge */ 266e3cc067bSJeremy Fitzhardinge BUG_ON(get_port_user(port) != NULL); 267e3cc067bSJeremy Fitzhardinge set_port_user(port, u); 2680edce91dSJeremy Fitzhardinge set_port_enabled(port, true); /* start enabled */ 269f7116284SIan Campbell 2700a4666b5SJeremy Fitzhardinge rc = bind_evtchn_to_irqhandler(port, evtchn_interrupt, IRQF_DISABLED, 2710a4666b5SJeremy Fitzhardinge u->name, (void *)(unsigned long)port); 2720a4666b5SJeremy Fitzhardinge if (rc >= 0) 273420eb554SDaniel De Graaf rc = evtchn_make_refcounted(port); 274e7e44e44SWei Liu else { 275e7e44e44SWei Liu /* bind failed, should close the port now */ 276e7e44e44SWei Liu struct evtchn_close close; 277e7e44e44SWei Liu close.port = port; 278e7e44e44SWei Liu if (HYPERVISOR_event_channel_op(EVTCHNOP_close, &close) != 0) 279e7e44e44SWei Liu BUG(); 280e7e44e44SWei Liu set_port_user(port, NULL); 281e7e44e44SWei Liu } 2820a4666b5SJeremy Fitzhardinge 283f7116284SIan Campbell return rc; 284f7116284SIan Campbell } 285f7116284SIan Campbell 286f7116284SIan Campbell static void evtchn_unbind_from_user(struct per_user_data *u, int port) 287f7116284SIan Campbell { 288f7116284SIan Campbell int irq = irq_from_evtchn(port); 289f7116284SIan Campbell 290e7e44e44SWei Liu BUG_ON(irq < 0); 291e7e44e44SWei Liu 292f7116284SIan Campbell unbind_from_irqhandler(irq, (void *)(unsigned long)port); 2930a4666b5SJeremy Fitzhardinge 294e3cc067bSJeremy Fitzhardinge set_port_user(port, NULL); 295f7116284SIan Campbell } 296f7116284SIan Campbell 297f7116284SIan Campbell static long evtchn_ioctl(struct file *file, 298f7116284SIan Campbell unsigned int cmd, unsigned long arg) 299f7116284SIan Campbell { 300f7116284SIan Campbell int rc; 301f7116284SIan Campbell struct per_user_data *u = file->private_data; 302f7116284SIan Campbell void __user *uarg = (void __user *) arg; 303f7116284SIan Campbell 3040a4666b5SJeremy Fitzhardinge /* Prevent bind from racing with unbind */ 3050a4666b5SJeremy Fitzhardinge mutex_lock(&u->bind_mutex); 3060a4666b5SJeremy Fitzhardinge 307f7116284SIan Campbell switch (cmd) { 308f7116284SIan Campbell case IOCTL_EVTCHN_BIND_VIRQ: { 309f7116284SIan Campbell struct ioctl_evtchn_bind_virq bind; 310f7116284SIan Campbell struct evtchn_bind_virq bind_virq; 311f7116284SIan Campbell 312f7116284SIan Campbell rc = -EFAULT; 313f7116284SIan Campbell if (copy_from_user(&bind, uarg, sizeof(bind))) 314f7116284SIan Campbell break; 315f7116284SIan Campbell 316f7116284SIan Campbell bind_virq.virq = bind.virq; 317f7116284SIan Campbell bind_virq.vcpu = 0; 318f7116284SIan Campbell rc = HYPERVISOR_event_channel_op(EVTCHNOP_bind_virq, 319f7116284SIan Campbell &bind_virq); 320f7116284SIan Campbell if (rc != 0) 321f7116284SIan Campbell break; 322f7116284SIan Campbell 323f7116284SIan Campbell rc = evtchn_bind_to_user(u, bind_virq.port); 324f7116284SIan Campbell if (rc == 0) 325f7116284SIan Campbell rc = bind_virq.port; 326f7116284SIan Campbell break; 327f7116284SIan Campbell } 328f7116284SIan Campbell 329f7116284SIan Campbell case IOCTL_EVTCHN_BIND_INTERDOMAIN: { 330f7116284SIan Campbell struct ioctl_evtchn_bind_interdomain bind; 331f7116284SIan Campbell struct evtchn_bind_interdomain bind_interdomain; 332f7116284SIan Campbell 333f7116284SIan Campbell rc = -EFAULT; 334f7116284SIan Campbell if (copy_from_user(&bind, uarg, sizeof(bind))) 335f7116284SIan Campbell break; 336f7116284SIan Campbell 337f7116284SIan Campbell bind_interdomain.remote_dom = bind.remote_domain; 338f7116284SIan Campbell bind_interdomain.remote_port = bind.remote_port; 339f7116284SIan Campbell rc = HYPERVISOR_event_channel_op(EVTCHNOP_bind_interdomain, 340f7116284SIan Campbell &bind_interdomain); 341f7116284SIan Campbell if (rc != 0) 342f7116284SIan Campbell break; 343f7116284SIan Campbell 344f7116284SIan Campbell rc = evtchn_bind_to_user(u, bind_interdomain.local_port); 345f7116284SIan Campbell if (rc == 0) 346f7116284SIan Campbell rc = bind_interdomain.local_port; 347f7116284SIan Campbell break; 348f7116284SIan Campbell } 349f7116284SIan Campbell 350f7116284SIan Campbell case IOCTL_EVTCHN_BIND_UNBOUND_PORT: { 351f7116284SIan Campbell struct ioctl_evtchn_bind_unbound_port bind; 352f7116284SIan Campbell struct evtchn_alloc_unbound alloc_unbound; 353f7116284SIan Campbell 354f7116284SIan Campbell rc = -EFAULT; 355f7116284SIan Campbell if (copy_from_user(&bind, uarg, sizeof(bind))) 356f7116284SIan Campbell break; 357f7116284SIan Campbell 358f7116284SIan Campbell alloc_unbound.dom = DOMID_SELF; 359f7116284SIan Campbell alloc_unbound.remote_dom = bind.remote_domain; 360f7116284SIan Campbell rc = HYPERVISOR_event_channel_op(EVTCHNOP_alloc_unbound, 361f7116284SIan Campbell &alloc_unbound); 362f7116284SIan Campbell if (rc != 0) 363f7116284SIan Campbell break; 364f7116284SIan Campbell 365f7116284SIan Campbell rc = evtchn_bind_to_user(u, alloc_unbound.port); 366f7116284SIan Campbell if (rc == 0) 367f7116284SIan Campbell rc = alloc_unbound.port; 368f7116284SIan Campbell break; 369f7116284SIan Campbell } 370f7116284SIan Campbell 371f7116284SIan Campbell case IOCTL_EVTCHN_UNBIND: { 372f7116284SIan Campbell struct ioctl_evtchn_unbind unbind; 373f7116284SIan Campbell 374f7116284SIan Campbell rc = -EFAULT; 375f7116284SIan Campbell if (copy_from_user(&unbind, uarg, sizeof(unbind))) 376f7116284SIan Campbell break; 377f7116284SIan Campbell 378f7116284SIan Campbell rc = -EINVAL; 379f7116284SIan Campbell if (unbind.port >= NR_EVENT_CHANNELS) 380f7116284SIan Campbell break; 381f7116284SIan Campbell 382f7116284SIan Campbell spin_lock_irq(&port_user_lock); 383f7116284SIan Campbell 384f7116284SIan Campbell rc = -ENOTCONN; 385e3cc067bSJeremy Fitzhardinge if (get_port_user(unbind.port) != u) { 386f7116284SIan Campbell spin_unlock_irq(&port_user_lock); 387f7116284SIan Campbell break; 388f7116284SIan Campbell } 389f7116284SIan Campbell 3903f5e554fSJeremy Fitzhardinge disable_irq(irq_from_evtchn(unbind.port)); 391f7116284SIan Campbell 392f7116284SIan Campbell spin_unlock_irq(&port_user_lock); 393f7116284SIan Campbell 3943f5e554fSJeremy Fitzhardinge evtchn_unbind_from_user(u, unbind.port); 3953f5e554fSJeremy Fitzhardinge 396f7116284SIan Campbell rc = 0; 397f7116284SIan Campbell break; 398f7116284SIan Campbell } 399f7116284SIan Campbell 400f7116284SIan Campbell case IOCTL_EVTCHN_NOTIFY: { 401f7116284SIan Campbell struct ioctl_evtchn_notify notify; 402f7116284SIan Campbell 403f7116284SIan Campbell rc = -EFAULT; 404f7116284SIan Campbell if (copy_from_user(¬ify, uarg, sizeof(notify))) 405f7116284SIan Campbell break; 406f7116284SIan Campbell 407f7116284SIan Campbell if (notify.port >= NR_EVENT_CHANNELS) { 408f7116284SIan Campbell rc = -EINVAL; 409e3cc067bSJeremy Fitzhardinge } else if (get_port_user(notify.port) != u) { 410f7116284SIan Campbell rc = -ENOTCONN; 411f7116284SIan Campbell } else { 412f7116284SIan Campbell notify_remote_via_evtchn(notify.port); 413f7116284SIan Campbell rc = 0; 414f7116284SIan Campbell } 415f7116284SIan Campbell break; 416f7116284SIan Campbell } 417f7116284SIan Campbell 418f7116284SIan Campbell case IOCTL_EVTCHN_RESET: { 419f7116284SIan Campbell /* Initialise the ring to empty. Clear errors. */ 420f7116284SIan Campbell mutex_lock(&u->ring_cons_mutex); 421f7116284SIan Campbell spin_lock_irq(&port_user_lock); 422f7116284SIan Campbell u->ring_cons = u->ring_prod = u->ring_overflow = 0; 423f7116284SIan Campbell spin_unlock_irq(&port_user_lock); 424f7116284SIan Campbell mutex_unlock(&u->ring_cons_mutex); 425f7116284SIan Campbell rc = 0; 426f7116284SIan Campbell break; 427f7116284SIan Campbell } 428f7116284SIan Campbell 429f7116284SIan Campbell default: 430f7116284SIan Campbell rc = -ENOSYS; 431f7116284SIan Campbell break; 432f7116284SIan Campbell } 4330a4666b5SJeremy Fitzhardinge mutex_unlock(&u->bind_mutex); 434f7116284SIan Campbell 435f7116284SIan Campbell return rc; 436f7116284SIan Campbell } 437f7116284SIan Campbell 438f7116284SIan Campbell static unsigned int evtchn_poll(struct file *file, poll_table *wait) 439f7116284SIan Campbell { 440f7116284SIan Campbell unsigned int mask = POLLOUT | POLLWRNORM; 441f7116284SIan Campbell struct per_user_data *u = file->private_data; 442f7116284SIan Campbell 443f7116284SIan Campbell poll_wait(file, &u->evtchn_wait, wait); 444f7116284SIan Campbell if (u->ring_cons != u->ring_prod) 445f7116284SIan Campbell mask |= POLLIN | POLLRDNORM; 446f7116284SIan Campbell if (u->ring_overflow) 447f7116284SIan Campbell mask = POLLERR; 448f7116284SIan Campbell return mask; 449f7116284SIan Campbell } 450f7116284SIan Campbell 451f7116284SIan Campbell static int evtchn_fasync(int fd, struct file *filp, int on) 452f7116284SIan Campbell { 453f7116284SIan Campbell struct per_user_data *u = filp->private_data; 454f7116284SIan Campbell return fasync_helper(fd, filp, on, &u->evtchn_async_queue); 455f7116284SIan Campbell } 456f7116284SIan Campbell 457f7116284SIan Campbell static int evtchn_open(struct inode *inode, struct file *filp) 458f7116284SIan Campbell { 459f7116284SIan Campbell struct per_user_data *u; 460f7116284SIan Campbell 461f7116284SIan Campbell u = kzalloc(sizeof(*u), GFP_KERNEL); 462f7116284SIan Campbell if (u == NULL) 463f7116284SIan Campbell return -ENOMEM; 464f7116284SIan Campbell 465f7116284SIan Campbell u->name = kasprintf(GFP_KERNEL, "evtchn:%s", current->comm); 466f7116284SIan Campbell if (u->name == NULL) { 467f7116284SIan Campbell kfree(u); 468f7116284SIan Campbell return -ENOMEM; 469f7116284SIan Campbell } 470f7116284SIan Campbell 471f7116284SIan Campbell init_waitqueue_head(&u->evtchn_wait); 472f7116284SIan Campbell 473f7116284SIan Campbell u->ring = (evtchn_port_t *)__get_free_page(GFP_KERNEL); 474f7116284SIan Campbell if (u->ring == NULL) { 475f7116284SIan Campbell kfree(u->name); 476f7116284SIan Campbell kfree(u); 477f7116284SIan Campbell return -ENOMEM; 478f7116284SIan Campbell } 479f7116284SIan Campbell 4800a4666b5SJeremy Fitzhardinge mutex_init(&u->bind_mutex); 481f7116284SIan Campbell mutex_init(&u->ring_cons_mutex); 482f7116284SIan Campbell 483f7116284SIan Campbell filp->private_data = u; 484f7116284SIan Campbell 4856eab04a8SJustin P. Mattock return nonseekable_open(inode, filp); 486f7116284SIan Campbell } 487f7116284SIan Campbell 488f7116284SIan Campbell static int evtchn_release(struct inode *inode, struct file *filp) 489f7116284SIan Campbell { 490f7116284SIan Campbell int i; 491f7116284SIan Campbell struct per_user_data *u = filp->private_data; 492f7116284SIan Campbell 493f7116284SIan Campbell spin_lock_irq(&port_user_lock); 494f7116284SIan Campbell 495f7116284SIan Campbell free_page((unsigned long)u->ring); 496f7116284SIan Campbell 497f7116284SIan Campbell for (i = 0; i < NR_EVENT_CHANNELS; i++) { 498e3cc067bSJeremy Fitzhardinge if (get_port_user(i) != u) 499f7116284SIan Campbell continue; 500f7116284SIan Campbell 5013f5e554fSJeremy Fitzhardinge disable_irq(irq_from_evtchn(i)); 502f7116284SIan Campbell } 503f7116284SIan Campbell 504f7116284SIan Campbell spin_unlock_irq(&port_user_lock); 505f7116284SIan Campbell 5063f5e554fSJeremy Fitzhardinge for (i = 0; i < NR_EVENT_CHANNELS; i++) { 5073f5e554fSJeremy Fitzhardinge if (get_port_user(i) != u) 5083f5e554fSJeremy Fitzhardinge continue; 5093f5e554fSJeremy Fitzhardinge 5103f5e554fSJeremy Fitzhardinge evtchn_unbind_from_user(get_port_user(i), i); 5113f5e554fSJeremy Fitzhardinge } 5123f5e554fSJeremy Fitzhardinge 513f7116284SIan Campbell kfree(u->name); 514f7116284SIan Campbell kfree(u); 515f7116284SIan Campbell 516f7116284SIan Campbell return 0; 517f7116284SIan Campbell } 518f7116284SIan Campbell 519f7116284SIan Campbell static const struct file_operations evtchn_fops = { 520f7116284SIan Campbell .owner = THIS_MODULE, 521f7116284SIan Campbell .read = evtchn_read, 522f7116284SIan Campbell .write = evtchn_write, 523f7116284SIan Campbell .unlocked_ioctl = evtchn_ioctl, 524f7116284SIan Campbell .poll = evtchn_poll, 525f7116284SIan Campbell .fasync = evtchn_fasync, 526f7116284SIan Campbell .open = evtchn_open, 527f7116284SIan Campbell .release = evtchn_release, 528bc7fc5e3SJeremy Fitzhardinge .llseek = no_llseek, 529f7116284SIan Campbell }; 530f7116284SIan Campbell 531f7116284SIan Campbell static struct miscdevice evtchn_miscdev = { 532f7116284SIan Campbell .minor = MISC_DYNAMIC_MINOR, 533376d908fSBastian Blank .name = "xen/evtchn", 534f7116284SIan Campbell .fops = &evtchn_fops, 535f7116284SIan Campbell }; 536f7116284SIan Campbell static int __init evtchn_init(void) 537f7116284SIan Campbell { 538f7116284SIan Campbell int err; 539f7116284SIan Campbell 540f7116284SIan Campbell if (!xen_domain()) 541f7116284SIan Campbell return -ENODEV; 542f7116284SIan Campbell 54393afe0b7SJeremy Fitzhardinge port_user = kcalloc(NR_EVENT_CHANNELS, sizeof(*port_user), GFP_KERNEL); 54493afe0b7SJeremy Fitzhardinge if (port_user == NULL) 54593afe0b7SJeremy Fitzhardinge return -ENOMEM; 54693afe0b7SJeremy Fitzhardinge 547f7116284SIan Campbell spin_lock_init(&port_user_lock); 548f7116284SIan Campbell 54918283ea7SWei Liu /* Create '/dev/xen/evtchn'. */ 550f7116284SIan Campbell err = misc_register(&evtchn_miscdev); 551f7116284SIan Campbell if (err != 0) { 552*283c0972SJoe Perches pr_err("Could not register /dev/xen/evtchn\n"); 553f7116284SIan Campbell return err; 554f7116284SIan Campbell } 555f7116284SIan Campbell 556*283c0972SJoe Perches pr_info("Event-channel device installed\n"); 557f7116284SIan Campbell 558f7116284SIan Campbell return 0; 559f7116284SIan Campbell } 560f7116284SIan Campbell 561f7116284SIan Campbell static void __exit evtchn_cleanup(void) 562f7116284SIan Campbell { 56393afe0b7SJeremy Fitzhardinge kfree(port_user); 56493afe0b7SJeremy Fitzhardinge port_user = NULL; 56593afe0b7SJeremy Fitzhardinge 566f7116284SIan Campbell misc_deregister(&evtchn_miscdev); 567f7116284SIan Campbell } 568f7116284SIan Campbell 569f7116284SIan Campbell module_init(evtchn_init); 570f7116284SIan Campbell module_exit(evtchn_cleanup); 571f7116284SIan Campbell 572f7116284SIan Campbell MODULE_LICENSE("GPL"); 573