evtchn.c (11e4afb49b7fa1fc8e1ffd850c1806dd86a08204) | evtchn.c (70697d540c0598ad023a391d4c895044db9a6624) |
---|---|
1/****************************************************************************** 2 * evtchn.c 3 * 4 * Driver for receiving and demuxing event-channel signals. 5 * 6 * Copyright (c) 2004-2005, K A Fraser 7 * Multi-process extensions Copyright (c) 2004, Steven Smith 8 * --- 24 unchanged lines hidden (view full) --- 33 34#include <linux/module.h> 35#include <linux/kernel.h> 36#include <linux/sched.h> 37#include <linux/slab.h> 38#include <linux/string.h> 39#include <linux/errno.h> 40#include <linux/fs.h> | 1/****************************************************************************** 2 * evtchn.c 3 * 4 * Driver for receiving and demuxing event-channel signals. 5 * 6 * Copyright (c) 2004-2005, K A Fraser 7 * Multi-process extensions Copyright (c) 2004, Steven Smith 8 * --- 24 unchanged lines hidden (view full) --- 33 34#include <linux/module.h> 35#include <linux/kernel.h> 36#include <linux/sched.h> 37#include <linux/slab.h> 38#include <linux/string.h> 39#include <linux/errno.h> 40#include <linux/fs.h> |
41#include <linux/errno.h> |
|
41#include <linux/miscdevice.h> 42#include <linux/major.h> 43#include <linux/proc_fs.h> 44#include <linux/stat.h> 45#include <linux/poll.h> 46#include <linux/irq.h> 47#include <linux/init.h> | 42#include <linux/miscdevice.h> 43#include <linux/major.h> 44#include <linux/proc_fs.h> 45#include <linux/stat.h> 46#include <linux/poll.h> 47#include <linux/irq.h> 48#include <linux/init.h> |
49#include <linux/gfp.h> |
|
48#include <linux/mutex.h> 49#include <linux/cpu.h> | 50#include <linux/mutex.h> 51#include <linux/cpu.h> |
50 51#include <xen/xen.h> | |
52#include <xen/events.h> 53#include <xen/evtchn.h> 54#include <asm/xen/hypervisor.h> 55 56struct per_user_data { 57 struct mutex bind_mutex; /* serialize bind/unbind operations */ 58 59 /* Notification ring, accessed via /dev/xen/evtchn. */ --- 4 unchanged lines hidden (view full) --- 64 struct mutex ring_cons_mutex; /* protect against concurrent readers */ 65 66 /* Processes wait on this queue when ring is empty. */ 67 wait_queue_head_t evtchn_wait; 68 struct fasync_struct *evtchn_async_queue; 69 const char *name; 70}; 71 | 52#include <xen/events.h> 53#include <xen/evtchn.h> 54#include <asm/xen/hypervisor.h> 55 56struct per_user_data { 57 struct mutex bind_mutex; /* serialize bind/unbind operations */ 58 59 /* Notification ring, accessed via /dev/xen/evtchn. */ --- 4 unchanged lines hidden (view full) --- 64 struct mutex ring_cons_mutex; /* protect against concurrent readers */ 65 66 /* Processes wait on this queue when ring is empty. */ 67 wait_queue_head_t evtchn_wait; 68 struct fasync_struct *evtchn_async_queue; 69 const char *name; 70}; 71 |
72/* Who's bound to each port? */ 73static struct per_user_data *port_user[NR_EVENT_CHANNELS]; | 72/* 73 * Who's bound to each port? This is logically an array of struct 74 * per_user_data *, but we encode the current enabled-state in bit 0. 75 */ 76static unsigned long *port_user; |
74static DEFINE_SPINLOCK(port_user_lock); /* protects port_user[] and ring_prod */ 75 | 77static DEFINE_SPINLOCK(port_user_lock); /* protects port_user[] and ring_prod */ 78 |
76irqreturn_t evtchn_interrupt(int irq, void *data) | 79static inline struct per_user_data *get_port_user(unsigned port) |
77{ | 80{ |
81 return (struct per_user_data *)(port_user[port] & ~1); 82} 83 84static inline void set_port_user(unsigned port, struct per_user_data *u) 85{ 86 port_user[port] = (unsigned long)u; 87} 88 89static inline bool get_port_enabled(unsigned port) 90{ 91 return port_user[port] & 1; 92} 93 94static inline void set_port_enabled(unsigned port, bool enabled) 95{ 96 if (enabled) 97 port_user[port] |= 1; 98 else 99 port_user[port] &= ~1; 100} 101 102static irqreturn_t evtchn_interrupt(int irq, void *data) 103{ |
|
78 unsigned int port = (unsigned long)data; 79 struct per_user_data *u; 80 81 spin_lock(&port_user_lock); 82 | 104 unsigned int port = (unsigned long)data; 105 struct per_user_data *u; 106 107 spin_lock(&port_user_lock); 108 |
83 u = port_user[port]; | 109 u = get_port_user(port); |
84 | 110 |
111 WARN(!get_port_enabled(port), 112 "Interrupt for port %d, but apparently not enabled; per-user %p\n", 113 port, u); 114 |
|
85 disable_irq_nosync(irq); | 115 disable_irq_nosync(irq); |
116 set_port_enabled(port, false); |
|
86 87 if ((u->ring_prod - u->ring_cons) < EVTCHN_RING_SIZE) { 88 u->ring[EVTCHN_RING_MASK(u->ring_prod)] = port; 89 wmb(); /* Ensure ring contents visible */ 90 if (u->ring_cons == u->ring_prod++) { 91 wake_up_interruptible(&u->evtchn_wait); 92 kill_fasync(&u->evtchn_async_queue, 93 SIGIO, POLL_IN); 94 } | 117 118 if ((u->ring_prod - u->ring_cons) < EVTCHN_RING_SIZE) { 119 u->ring[EVTCHN_RING_MASK(u->ring_prod)] = port; 120 wmb(); /* Ensure ring contents visible */ 121 if (u->ring_cons == u->ring_prod++) { 122 wake_up_interruptible(&u->evtchn_wait); 123 kill_fasync(&u->evtchn_async_queue, 124 SIGIO, POLL_IN); 125 } |
95 } else { | 126 } else |
96 u->ring_overflow = 1; | 127 u->ring_overflow = 1; |
97 } | |
98 99 spin_unlock(&port_user_lock); 100 101 return IRQ_HANDLED; 102} 103 104static ssize_t evtchn_read(struct file *file, char __user *buf, 105 size_t count, loff_t *ppos) --- 87 unchanged lines hidden (view full) --- 193 if (count > PAGE_SIZE) 194 count = PAGE_SIZE; 195 196 rc = -EFAULT; 197 if (copy_from_user(kbuf, buf, count) != 0) 198 goto out; 199 200 spin_lock_irq(&port_user_lock); | 128 129 spin_unlock(&port_user_lock); 130 131 return IRQ_HANDLED; 132} 133 134static ssize_t evtchn_read(struct file *file, char __user *buf, 135 size_t count, loff_t *ppos) --- 87 unchanged lines hidden (view full) --- 223 if (count > PAGE_SIZE) 224 count = PAGE_SIZE; 225 226 rc = -EFAULT; 227 if (copy_from_user(kbuf, buf, count) != 0) 228 goto out; 229 230 spin_lock_irq(&port_user_lock); |
201 for (i = 0; i < (count/sizeof(evtchn_port_t)); i++) 202 if ((kbuf[i] < NR_EVENT_CHANNELS) && (port_user[kbuf[i]] == u)) 203 enable_irq(irq_from_evtchn(kbuf[i])); | 231 232 for (i = 0; i < (count/sizeof(evtchn_port_t)); i++) { 233 unsigned port = kbuf[i]; 234 235 if (port < NR_EVENT_CHANNELS && 236 get_port_user(port) == u && 237 !get_port_enabled(port)) { 238 set_port_enabled(port, true); 239 enable_irq(irq_from_evtchn(port)); 240 } 241 } 242 |
204 spin_unlock_irq(&port_user_lock); 205 206 rc = count; 207 208 out: 209 free_page((unsigned long)kbuf); 210 return rc; 211} --- 5 unchanged lines hidden (view full) --- 217 /* 218 * Ports are never reused, so every caller should pass in a 219 * unique port. 220 * 221 * (Locking not necessary because we haven't registered the 222 * interrupt handler yet, and our caller has already 223 * serialized bind operations.) 224 */ | 243 spin_unlock_irq(&port_user_lock); 244 245 rc = count; 246 247 out: 248 free_page((unsigned long)kbuf); 249 return rc; 250} --- 5 unchanged lines hidden (view full) --- 256 /* 257 * Ports are never reused, so every caller should pass in a 258 * unique port. 259 * 260 * (Locking not necessary because we haven't registered the 261 * interrupt handler yet, and our caller has already 262 * serialized bind operations.) 263 */ |
225 BUG_ON(port_user[port] != NULL); 226 port_user[port] = u; | 264 BUG_ON(get_port_user(port) != NULL); 265 set_port_user(port, u); 266 set_port_enabled(port, true); /* start enabled */ |
227 228 rc = bind_evtchn_to_irqhandler(port, evtchn_interrupt, IRQF_DISABLED, 229 u->name, (void *)(unsigned long)port); 230 if (rc >= 0) 231 rc = 0; 232 233 return rc; 234} 235 236static void evtchn_unbind_from_user(struct per_user_data *u, int port) 237{ 238 int irq = irq_from_evtchn(port); 239 240 unbind_from_irqhandler(irq, (void *)(unsigned long)port); 241 | 267 268 rc = bind_evtchn_to_irqhandler(port, evtchn_interrupt, IRQF_DISABLED, 269 u->name, (void *)(unsigned long)port); 270 if (rc >= 0) 271 rc = 0; 272 273 return rc; 274} 275 276static void evtchn_unbind_from_user(struct per_user_data *u, int port) 277{ 278 int irq = irq_from_evtchn(port); 279 280 unbind_from_irqhandler(irq, (void *)(unsigned long)port); 281 |
242 /* make sure we unbind the irq handler before clearing the port */ 243 barrier(); 244 245 port_user[port] = NULL; | 282 set_port_user(port, NULL); |
246} 247 248static long evtchn_ioctl(struct file *file, 249 unsigned int cmd, unsigned long arg) 250{ 251 int rc; 252 struct per_user_data *u = file->private_data; 253 void __user *uarg = (void __user *) arg; --- 74 unchanged lines hidden (view full) --- 328 329 rc = -EINVAL; 330 if (unbind.port >= NR_EVENT_CHANNELS) 331 break; 332 333 spin_lock_irq(&port_user_lock); 334 335 rc = -ENOTCONN; | 283} 284 285static long evtchn_ioctl(struct file *file, 286 unsigned int cmd, unsigned long arg) 287{ 288 int rc; 289 struct per_user_data *u = file->private_data; 290 void __user *uarg = (void __user *) arg; --- 74 unchanged lines hidden (view full) --- 365 366 rc = -EINVAL; 367 if (unbind.port >= NR_EVENT_CHANNELS) 368 break; 369 370 spin_lock_irq(&port_user_lock); 371 372 rc = -ENOTCONN; |
336 if (port_user[unbind.port] != u) { | 373 if (get_port_user(unbind.port) != u) { |
337 spin_unlock_irq(&port_user_lock); 338 break; 339 } 340 | 374 spin_unlock_irq(&port_user_lock); 375 break; 376 } 377 |
341 evtchn_unbind_from_user(u, unbind.port); | 378 disable_irq(irq_from_evtchn(unbind.port)); |
342 343 spin_unlock_irq(&port_user_lock); 344 | 379 380 spin_unlock_irq(&port_user_lock); 381 |
382 evtchn_unbind_from_user(u, unbind.port); 383 |
|
345 rc = 0; 346 break; 347 } 348 349 case IOCTL_EVTCHN_NOTIFY: { 350 struct ioctl_evtchn_notify notify; 351 352 rc = -EFAULT; 353 if (copy_from_user(¬ify, uarg, sizeof(notify))) 354 break; 355 356 if (notify.port >= NR_EVENT_CHANNELS) { 357 rc = -EINVAL; | 384 rc = 0; 385 break; 386 } 387 388 case IOCTL_EVTCHN_NOTIFY: { 389 struct ioctl_evtchn_notify notify; 390 391 rc = -EFAULT; 392 if (copy_from_user(¬ify, uarg, sizeof(notify))) 393 break; 394 395 if (notify.port >= NR_EVENT_CHANNELS) { 396 rc = -EINVAL; |
358 } else if (port_user[notify.port] != u) { | 397 } else if (get_port_user(notify.port) != u) { |
359 rc = -ENOTCONN; 360 } else { 361 notify_remote_via_evtchn(notify.port); 362 rc = 0; 363 } 364 break; 365 } 366 --- 72 unchanged lines hidden (view full) --- 439 int i; 440 struct per_user_data *u = filp->private_data; 441 442 spin_lock_irq(&port_user_lock); 443 444 free_page((unsigned long)u->ring); 445 446 for (i = 0; i < NR_EVENT_CHANNELS; i++) { | 398 rc = -ENOTCONN; 399 } else { 400 notify_remote_via_evtchn(notify.port); 401 rc = 0; 402 } 403 break; 404 } 405 --- 72 unchanged lines hidden (view full) --- 478 int i; 479 struct per_user_data *u = filp->private_data; 480 481 spin_lock_irq(&port_user_lock); 482 483 free_page((unsigned long)u->ring); 484 485 for (i = 0; i < NR_EVENT_CHANNELS; i++) { |
447 if (port_user[i] != u) | 486 if (get_port_user(i) != u) |
448 continue; 449 | 487 continue; 488 |
450 evtchn_unbind_from_user(port_user[i], i); | 489 disable_irq(irq_from_evtchn(i)); |
451 } 452 453 spin_unlock_irq(&port_user_lock); 454 | 490 } 491 492 spin_unlock_irq(&port_user_lock); 493 |
494 for (i = 0; i < NR_EVENT_CHANNELS; i++) { 495 if (get_port_user(i) != u) 496 continue; 497 498 evtchn_unbind_from_user(get_port_user(i), i); 499 } 500 |
|
455 kfree(u->name); 456 kfree(u); 457 458 return 0; 459} 460 461static const struct file_operations evtchn_fops = { 462 .owner = THIS_MODULE, 463 .read = evtchn_read, 464 .write = evtchn_write, 465 .unlocked_ioctl = evtchn_ioctl, 466 .poll = evtchn_poll, 467 .fasync = evtchn_fasync, 468 .open = evtchn_open, 469 .release = evtchn_release, 470}; 471 472static struct miscdevice evtchn_miscdev = { 473 .minor = MISC_DYNAMIC_MINOR, | 501 kfree(u->name); 502 kfree(u); 503 504 return 0; 505} 506 507static const struct file_operations evtchn_fops = { 508 .owner = THIS_MODULE, 509 .read = evtchn_read, 510 .write = evtchn_write, 511 .unlocked_ioctl = evtchn_ioctl, 512 .poll = evtchn_poll, 513 .fasync = evtchn_fasync, 514 .open = evtchn_open, 515 .release = evtchn_release, 516}; 517 518static struct miscdevice evtchn_miscdev = { 519 .minor = MISC_DYNAMIC_MINOR, |
474 .name = "evtchn", | 520 .name = "xen/evtchn", |
475 .fops = &evtchn_fops, 476}; 477static int __init evtchn_init(void) 478{ 479 int err; 480 481 if (!xen_domain()) 482 return -ENODEV; 483 | 521 .fops = &evtchn_fops, 522}; 523static int __init evtchn_init(void) 524{ 525 int err; 526 527 if (!xen_domain()) 528 return -ENODEV; 529 |
530 port_user = kcalloc(NR_EVENT_CHANNELS, sizeof(*port_user), GFP_KERNEL); 531 if (port_user == NULL) 532 return -ENOMEM; 533 |
|
484 spin_lock_init(&port_user_lock); | 534 spin_lock_init(&port_user_lock); |
485 memset(port_user, 0, sizeof(port_user)); | |
486 487 /* Create '/dev/misc/evtchn'. */ 488 err = misc_register(&evtchn_miscdev); 489 if (err != 0) { 490 printk(KERN_ALERT "Could not register /dev/misc/evtchn\n"); 491 return err; 492 } 493 494 printk(KERN_INFO "Event-channel device installed.\n"); 495 496 return 0; 497} 498 499static void __exit evtchn_cleanup(void) 500{ | 535 536 /* Create '/dev/misc/evtchn'. */ 537 err = misc_register(&evtchn_miscdev); 538 if (err != 0) { 539 printk(KERN_ALERT "Could not register /dev/misc/evtchn\n"); 540 return err; 541 } 542 543 printk(KERN_INFO "Event-channel device installed.\n"); 544 545 return 0; 546} 547 548static void __exit evtchn_cleanup(void) 549{ |
550 kfree(port_user); 551 port_user = NULL; 552 |
|
501 misc_deregister(&evtchn_miscdev); 502} 503 504module_init(evtchn_init); 505module_exit(evtchn_cleanup); 506 507MODULE_LICENSE("GPL"); | 553 misc_deregister(&evtchn_miscdev); 554} 555 556module_init(evtchn_init); 557module_exit(evtchn_cleanup); 558 559MODULE_LICENSE("GPL"); |