xref: /openbmc/linux/drivers/xen/evtchn.c (revision f7116284c734f3a47180cd9c907944a1837ccb3c)
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(&notify, 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