1273474Sroyger/******************************************************************************
2273474Sroyger * evtchn.c
3273474Sroyger *
4273474Sroyger * Driver for receiving and demuxing event-channel signals.
5273474Sroyger *
6273474Sroyger * Copyright (c) 2004-2005, K A Fraser
7273474Sroyger * Multi-process extensions Copyright (c) 2004, Steven Smith
8273474Sroyger * FreeBSD port Copyright (c) 2014, Roger Pau Monn��
9273474Sroyger * Fetched from git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
10273474Sroyger * File: drivers/xen/evtchn.c
11273474Sroyger * Git commit: 0dc0064add422bc0ef5165ebe9ece3052bbd457d
12273474Sroyger *
13273474Sroyger * This program is free software; you can redistribute it and/or
14273474Sroyger * modify it under the terms of the GNU General Public License version 2
15273474Sroyger * as published by the Free Software Foundation; or, when distributed
16273474Sroyger * separately from the Linux kernel or incorporated into other
17273474Sroyger * software packages, subject to the following license:
18273474Sroyger *
19273474Sroyger * Permission is hereby granted, free of charge, to any person obtaining a copy
20273474Sroyger * of this source file (the "Software"), to deal in the Software without
21273474Sroyger * restriction, including without limitation the rights to use, copy, modify,
22273474Sroyger * merge, publish, distribute, sublicense, and/or sell copies of the Software,
23273474Sroyger * and to permit persons to whom the Software is furnished to do so, subject to
24273474Sroyger * the following conditions:
25273474Sroyger *
26273474Sroyger * The above copyright notice and this permission notice shall be included in
27273474Sroyger * all copies or substantial portions of the Software.
28273474Sroyger *
29273474Sroyger * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
30273474Sroyger * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
31273474Sroyger * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
32273474Sroyger * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
33273474Sroyger * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
34273474Sroyger * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
35273474Sroyger * IN THE SOFTWARE.
36273474Sroyger */
37273474Sroyger
38273474Sroyger#include <sys/cdefs.h>
39273474Sroyger__FBSDID("$FreeBSD: releng/11.0/sys/dev/xen/evtchn/evtchn_dev.c 299353 2016-05-10 10:26:07Z trasz $");
40273474Sroyger
41273474Sroyger#include <sys/param.h>
42273474Sroyger#include <sys/systm.h>
43273474Sroyger#include <sys/uio.h>
44273474Sroyger#include <sys/bus.h>
45273474Sroyger#include <sys/malloc.h>
46273474Sroyger#include <sys/kernel.h>
47273474Sroyger#include <sys/lock.h>
48273474Sroyger#include <sys/mutex.h>
49273474Sroyger#include <sys/sx.h>
50273474Sroyger#include <sys/selinfo.h>
51273474Sroyger#include <sys/poll.h>
52273474Sroyger#include <sys/conf.h>
53273474Sroyger#include <sys/fcntl.h>
54273474Sroyger#include <sys/ioccom.h>
55273474Sroyger#include <sys/rman.h>
56273474Sroyger#include <sys/tree.h>
57273474Sroyger#include <sys/module.h>
58273474Sroyger#include <sys/filio.h>
59273474Sroyger#include <sys/vnode.h>
60273474Sroyger
61273474Sroyger#include <machine/intr_machdep.h>
62273474Sroyger#include <machine/xen/synch_bitops.h>
63273474Sroyger
64273474Sroyger#include <xen/xen-os.h>
65273474Sroyger#include <xen/evtchn.h>
66273474Sroyger#include <xen/xen_intr.h>
67273474Sroyger
68273474Sroyger#include <xen/evtchn/evtchnvar.h>
69273474Sroyger
70273474SroygerMALLOC_DEFINE(M_EVTCHN, "evtchn_dev", "Xen event channel user-space device");
71273474Sroyger
72273474Sroygerstruct user_evtchn;
73273474Sroyger
74273474Sroygerstatic int evtchn_cmp(struct user_evtchn *u1, struct user_evtchn *u2);
75273474Sroyger
76273474SroygerRB_HEAD(evtchn_tree, user_evtchn);
77273474Sroyger
78273474Sroygerstruct per_user_data {
79273474Sroyger	struct mtx bind_mutex; /* serialize bind/unbind operations */
80273474Sroyger	struct evtchn_tree evtchns;
81273474Sroyger
82273474Sroyger	/* Notification ring, accessed via /dev/xen/evtchn. */
83273474Sroyger#define EVTCHN_RING_SIZE     (PAGE_SIZE / sizeof(evtchn_port_t))
84273474Sroyger#define EVTCHN_RING_MASK(_i) ((_i)&(EVTCHN_RING_SIZE-1))
85273474Sroyger	evtchn_port_t *ring;
86273474Sroyger	unsigned int ring_cons, ring_prod, ring_overflow;
87273474Sroyger	struct sx ring_cons_mutex; /* protect against concurrent readers */
88273474Sroyger	struct mtx ring_prod_mutex; /* product against concurrent interrupts */
89273474Sroyger	struct selinfo ev_rsel;
90273474Sroyger};
91273474Sroyger
92273474Sroygerstruct user_evtchn {
93273474Sroyger	RB_ENTRY(user_evtchn) node;
94273474Sroyger	struct per_user_data *user;
95273474Sroyger	evtchn_port_t port;
96273474Sroyger	xen_intr_handle_t handle;
97273474Sroyger	bool enabled;
98273474Sroyger};
99273474Sroyger
100273474SroygerRB_GENERATE_STATIC(evtchn_tree, user_evtchn, node, evtchn_cmp);
101273474Sroyger
102273474Sroygerstatic device_t evtchn_dev;
103273474Sroyger
104273474Sroygerstatic d_read_t      evtchn_read;
105273474Sroygerstatic d_write_t     evtchn_write;
106273474Sroygerstatic d_ioctl_t     evtchn_ioctl;
107273474Sroygerstatic d_poll_t      evtchn_poll;
108273474Sroygerstatic d_open_t      evtchn_open;
109273474Sroyger
110273474Sroygerstatic void evtchn_release(void *arg);
111273474Sroyger
112273474Sroygerstatic struct cdevsw evtchn_devsw = {
113273474Sroyger	.d_version = D_VERSION,
114273474Sroyger	.d_open = evtchn_open,
115273474Sroyger	.d_read = evtchn_read,
116273474Sroyger	.d_write = evtchn_write,
117273474Sroyger	.d_ioctl = evtchn_ioctl,
118273474Sroyger	.d_poll = evtchn_poll,
119273474Sroyger	.d_name = "evtchn",
120273474Sroyger};
121273474Sroyger
122273474Sroyger/*------------------------- Red-black tree helpers ---------------------------*/
123273474Sroygerstatic int
124273474Sroygerevtchn_cmp(struct user_evtchn *u1, struct user_evtchn *u2)
125273474Sroyger{
126273474Sroyger
127273474Sroyger	return (u1->port - u2->port);
128273474Sroyger}
129273474Sroyger
130273474Sroygerstatic struct user_evtchn *
131273474Sroygerfind_evtchn(struct per_user_data *u, evtchn_port_t port)
132273474Sroyger{
133273474Sroyger	struct user_evtchn tmp = {
134273474Sroyger		.port = port,
135273474Sroyger	};
136273474Sroyger
137273474Sroyger	return (RB_FIND(evtchn_tree, &u->evtchns, &tmp));
138273474Sroyger}
139273474Sroyger
140273474Sroyger/*--------------------------- Interrupt handlers -----------------------------*/
141273474Sroygerstatic int
142273474Sroygerevtchn_filter(void *arg)
143273474Sroyger{
144273474Sroyger	struct user_evtchn *evtchn;
145273474Sroyger
146273474Sroyger	evtchn = arg;
147273474Sroyger
148273474Sroyger	if (!evtchn->enabled && bootverbose) {
149273474Sroyger		device_printf(evtchn_dev,
150273474Sroyger		    "Received upcall for disabled event channel %d\n",
151273474Sroyger		    evtchn->port);
152273474Sroyger	}
153273474Sroyger
154273474Sroyger	evtchn_mask_port(evtchn->port);
155273474Sroyger	evtchn->enabled = false;
156273474Sroyger
157273474Sroyger	return (FILTER_SCHEDULE_THREAD);
158273474Sroyger}
159273474Sroyger
160273474Sroygerstatic void
161273474Sroygerevtchn_interrupt(void *arg)
162273474Sroyger{
163273474Sroyger	struct user_evtchn *evtchn;
164273474Sroyger	struct per_user_data *u;
165273474Sroyger
166273474Sroyger	evtchn = arg;
167273474Sroyger	u = evtchn->user;
168273474Sroyger
169273474Sroyger	/*
170273474Sroyger	 * Protect against concurrent events using this handler
171273474Sroyger	 * on different CPUs.
172273474Sroyger	 */
173273474Sroyger	mtx_lock(&u->ring_prod_mutex);
174273474Sroyger	if ((u->ring_prod - u->ring_cons) < EVTCHN_RING_SIZE) {
175273474Sroyger		u->ring[EVTCHN_RING_MASK(u->ring_prod)] = evtchn->port;
176273474Sroyger		wmb(); /* Ensure ring contents visible */
177273474Sroyger		if (u->ring_cons == u->ring_prod++) {
178273474Sroyger			wakeup(u);
179273474Sroyger			selwakeup(&u->ev_rsel);
180273474Sroyger		}
181273474Sroyger	} else
182273474Sroyger		u->ring_overflow = 1;
183273474Sroyger	mtx_unlock(&u->ring_prod_mutex);
184273474Sroyger}
185273474Sroyger
186273474Sroyger/*------------------------- Character device methods -------------------------*/
187273474Sroygerstatic int
188273474Sroygerevtchn_open(struct cdev *dev, int flag, int otyp, struct thread *td)
189273474Sroyger{
190273474Sroyger	struct per_user_data *u;
191273474Sroyger	int error;
192273474Sroyger
193273474Sroyger	u = malloc(sizeof(*u), M_EVTCHN, M_WAITOK | M_ZERO);
194273474Sroyger	u->ring = malloc(PAGE_SIZE, M_EVTCHN, M_WAITOK | M_ZERO);
195273474Sroyger
196273474Sroyger	/* Initialize locks */
197273474Sroyger	mtx_init(&u->bind_mutex, "evtchn_bind_mutex", NULL, MTX_DEF);
198273474Sroyger	sx_init(&u->ring_cons_mutex, "evtchn_ringc_sx");
199273474Sroyger	mtx_init(&u->ring_prod_mutex, "evtchn_ringp_mutex", NULL, MTX_DEF);
200273474Sroyger
201273474Sroyger	/* Initialize red-black tree. */
202273474Sroyger	RB_INIT(&u->evtchns);
203273474Sroyger
204273474Sroyger	/* Assign the allocated per_user_data to this open instance. */
205273474Sroyger	error = devfs_set_cdevpriv(u, evtchn_release);
206273474Sroyger	if (error != 0) {
207273474Sroyger		mtx_destroy(&u->bind_mutex);
208273474Sroyger		mtx_destroy(&u->ring_prod_mutex);
209273474Sroyger		sx_destroy(&u->ring_cons_mutex);
210273474Sroyger		free(u->ring, M_EVTCHN);
211273474Sroyger		free(u, M_EVTCHN);
212273474Sroyger	}
213273474Sroyger
214273474Sroyger	return (error);
215273474Sroyger}
216273474Sroyger
217273474Sroygerstatic void
218273474Sroygerevtchn_release(void *arg)
219273474Sroyger{
220273474Sroyger	struct per_user_data *u;
221273474Sroyger	struct user_evtchn *evtchn, *tmp;
222273474Sroyger
223273474Sroyger	u = arg;
224273474Sroyger
225273474Sroyger	seldrain(&u->ev_rsel);
226273474Sroyger
227273474Sroyger	RB_FOREACH_SAFE(evtchn, evtchn_tree, &u->evtchns, tmp) {
228273474Sroyger		xen_intr_unbind(&evtchn->handle);
229273474Sroyger
230273474Sroyger		RB_REMOVE(evtchn_tree, &u->evtchns, evtchn);
231273474Sroyger		free(evtchn, M_EVTCHN);
232273474Sroyger	}
233273474Sroyger
234273474Sroyger	mtx_destroy(&u->bind_mutex);
235273474Sroyger	mtx_destroy(&u->ring_prod_mutex);
236273474Sroyger	sx_destroy(&u->ring_cons_mutex);
237273474Sroyger	free(u->ring, M_EVTCHN);
238273474Sroyger	free(u, M_EVTCHN);
239273474Sroyger}
240273474Sroyger
241273474Sroygerstatic int
242273474Sroygerevtchn_read(struct cdev *dev, struct uio *uio, int ioflag)
243273474Sroyger{
244273474Sroyger	int error, count;
245273474Sroyger	unsigned int c, p, bytes1 = 0, bytes2 = 0;
246273474Sroyger	struct per_user_data *u;
247273474Sroyger
248273474Sroyger	error = devfs_get_cdevpriv((void **)&u);
249273474Sroyger	if (error != 0)
250273474Sroyger		return (EINVAL);
251273474Sroyger
252273474Sroyger	/* Whole number of ports. */
253273474Sroyger	count = uio->uio_resid;
254273474Sroyger	count &= ~(sizeof(evtchn_port_t)-1);
255273474Sroyger
256273474Sroyger	if (count == 0)
257273474Sroyger		return (0);
258273474Sroyger
259273474Sroyger	if (count > PAGE_SIZE)
260273474Sroyger		count = PAGE_SIZE;
261273474Sroyger
262273474Sroyger	sx_xlock(&u->ring_cons_mutex);
263273474Sroyger	for (;;) {
264273474Sroyger		error = EFBIG;
265273474Sroyger		if (u->ring_overflow)
266273474Sroyger			goto unlock_out;
267273474Sroyger
268273474Sroyger		c = u->ring_cons;
269273474Sroyger		p = u->ring_prod;
270273474Sroyger		if (c != p)
271273474Sroyger			break;
272273474Sroyger
273273474Sroyger		if (ioflag & IO_NDELAY) {
274273474Sroyger			sx_xunlock(&u->ring_cons_mutex);
275273474Sroyger			return (EWOULDBLOCK);
276273474Sroyger		}
277273474Sroyger
278273474Sroyger		error = sx_sleep(u, &u->ring_cons_mutex, PCATCH, "evtchw", 0);
279273474Sroyger		if ((error != 0) && (error != EWOULDBLOCK))
280273474Sroyger			return (error);
281273474Sroyger	}
282273474Sroyger
283273474Sroyger	/* Byte lengths of two chunks. Chunk split (if any) is at ring wrap. */
284273474Sroyger	if (((c ^ p) & EVTCHN_RING_SIZE) != 0) {
285273474Sroyger		bytes1 = (EVTCHN_RING_SIZE - EVTCHN_RING_MASK(c)) *
286273474Sroyger		    sizeof(evtchn_port_t);
287273474Sroyger		bytes2 = EVTCHN_RING_MASK(p) * sizeof(evtchn_port_t);
288273474Sroyger	} else {
289273474Sroyger		bytes1 = (p - c) * sizeof(evtchn_port_t);
290273474Sroyger		bytes2 = 0;
291273474Sroyger	}
292273474Sroyger
293273474Sroyger	/* Truncate chunks according to caller's maximum byte count. */
294273474Sroyger	if (bytes1 > count) {
295273474Sroyger		bytes1 = count;
296273474Sroyger		bytes2 = 0;
297273474Sroyger	} else if ((bytes1 + bytes2) > count) {
298273474Sroyger		bytes2 = count - bytes1;
299273474Sroyger	}
300273474Sroyger
301273474Sroyger	error = EFAULT;
302273474Sroyger	rmb(); /* Ensure that we see the port before we copy it. */
303273474Sroyger
304273474Sroyger	if (uiomove(&u->ring[EVTCHN_RING_MASK(c)], bytes1, uio) ||
305273474Sroyger	    ((bytes2 != 0) && uiomove(&u->ring[0], bytes2, uio)))
306273474Sroyger		goto unlock_out;
307273474Sroyger
308273474Sroyger	u->ring_cons += (bytes1 + bytes2) / sizeof(evtchn_port_t);
309273474Sroyger	error = 0;
310273474Sroyger
311273474Sroygerunlock_out:
312273474Sroyger	sx_xunlock(&u->ring_cons_mutex);
313273474Sroyger	return (error);
314273474Sroyger}
315273474Sroyger
316273474Sroygerstatic int
317273474Sroygerevtchn_write(struct cdev *dev, struct uio *uio, int ioflag)
318273474Sroyger{
319273474Sroyger	int error, i, count;
320273474Sroyger	evtchn_port_t *kbuf;
321273474Sroyger	struct per_user_data *u;
322273474Sroyger
323273474Sroyger	error = devfs_get_cdevpriv((void **)&u);
324273474Sroyger	if (error != 0)
325273474Sroyger		return (EINVAL);
326273474Sroyger
327273474Sroyger	kbuf = malloc(PAGE_SIZE, M_EVTCHN, M_WAITOK);
328273474Sroyger
329273474Sroyger	count = uio->uio_resid;
330273474Sroyger	/* Whole number of ports. */
331273474Sroyger	count &= ~(sizeof(evtchn_port_t)-1);
332273474Sroyger
333273474Sroyger	error = 0;
334273474Sroyger	if (count == 0)
335273474Sroyger		goto out;
336273474Sroyger
337273474Sroyger	if (count > PAGE_SIZE)
338273474Sroyger		count = PAGE_SIZE;
339273474Sroyger
340273474Sroyger	error = uiomove(kbuf, count, uio);
341273474Sroyger	if (error != 0)
342273474Sroyger		goto out;
343273474Sroyger
344273474Sroyger	mtx_lock(&u->bind_mutex);
345273474Sroyger
346273474Sroyger	for (i = 0; i < (count/sizeof(evtchn_port_t)); i++) {
347273474Sroyger		evtchn_port_t port = kbuf[i];
348273474Sroyger		struct user_evtchn *evtchn;
349273474Sroyger
350273474Sroyger		evtchn = find_evtchn(u, port);
351273474Sroyger		if (evtchn && !evtchn->enabled) {
352273474Sroyger			evtchn->enabled = true;
353273474Sroyger			evtchn_unmask_port(evtchn->port);
354273474Sroyger		}
355273474Sroyger	}
356273474Sroyger
357273474Sroyger	mtx_unlock(&u->bind_mutex);
358273474Sroyger	error = 0;
359273474Sroyger
360273474Sroygerout:
361273474Sroyger	free(kbuf, M_EVTCHN);
362273474Sroyger	return (error);
363273474Sroyger}
364273474Sroyger
365273474Sroygerstatic inline int
366273474Sroygerevtchn_bind_user_port(struct per_user_data *u, struct user_evtchn *evtchn)
367273474Sroyger{
368273474Sroyger	int error;
369273474Sroyger
370273474Sroyger	evtchn->port = xen_intr_port(evtchn->handle);
371273474Sroyger	evtchn->user = u;
372273474Sroyger	evtchn->enabled = true;
373273474Sroyger	mtx_lock(&u->bind_mutex);
374273474Sroyger	RB_INSERT(evtchn_tree, &u->evtchns, evtchn);
375273474Sroyger	mtx_unlock(&u->bind_mutex);
376273474Sroyger	error = xen_intr_add_handler(evtchn_dev, evtchn_filter,
377273474Sroyger	    evtchn_interrupt, evtchn, INTR_TYPE_MISC | INTR_MPSAFE,
378273474Sroyger	    evtchn->handle);
379273474Sroyger	if (error != 0) {
380273474Sroyger		xen_intr_unbind(&evtchn->handle);
381273474Sroyger		mtx_lock(&u->bind_mutex);
382273474Sroyger		RB_REMOVE(evtchn_tree, &u->evtchns, evtchn);
383273474Sroyger		mtx_unlock(&u->bind_mutex);
384273474Sroyger		free(evtchn, M_EVTCHN);
385273474Sroyger	}
386273474Sroyger	return (error);
387273474Sroyger}
388273474Sroyger
389273474Sroygerstatic int
390273474Sroygerevtchn_ioctl(struct cdev *dev, unsigned long cmd, caddr_t arg,
391273474Sroyger    int mode, struct thread *td __unused)
392273474Sroyger{
393273474Sroyger	struct per_user_data *u;
394273474Sroyger	int error;
395273474Sroyger
396273474Sroyger	error = devfs_get_cdevpriv((void **)&u);
397273474Sroyger	if (error != 0)
398273474Sroyger		return (EINVAL);
399273474Sroyger
400273474Sroyger	switch (cmd) {
401273474Sroyger	case IOCTL_EVTCHN_BIND_VIRQ: {
402273474Sroyger		struct ioctl_evtchn_bind_virq *bind;
403273474Sroyger		struct user_evtchn *evtchn;
404273474Sroyger
405273474Sroyger		evtchn = malloc(sizeof(*evtchn), M_EVTCHN, M_WAITOK | M_ZERO);
406273474Sroyger
407273474Sroyger		bind = (struct ioctl_evtchn_bind_virq *)arg;
408273474Sroyger
409273474Sroyger		error = xen_intr_bind_virq(evtchn_dev, bind->virq, 0,
410273474Sroyger		    NULL, NULL, NULL, 0, &evtchn->handle);
411273474Sroyger		if (error != 0) {
412273474Sroyger			free(evtchn, M_EVTCHN);
413273474Sroyger			break;
414273474Sroyger		}
415273474Sroyger		error = evtchn_bind_user_port(u, evtchn);
416273474Sroyger		if (error != 0)
417273474Sroyger			break;
418273474Sroyger		bind->port = evtchn->port;
419273474Sroyger		break;
420273474Sroyger	}
421273474Sroyger
422273474Sroyger	case IOCTL_EVTCHN_BIND_INTERDOMAIN: {
423273474Sroyger		struct ioctl_evtchn_bind_interdomain *bind;
424273474Sroyger		struct user_evtchn *evtchn;
425273474Sroyger
426273474Sroyger		evtchn = malloc(sizeof(*evtchn), M_EVTCHN, M_WAITOK | M_ZERO);
427273474Sroyger
428273474Sroyger		bind = (struct ioctl_evtchn_bind_interdomain *)arg;
429273474Sroyger
430273474Sroyger		error = xen_intr_bind_remote_port(evtchn_dev,
431273474Sroyger		    bind->remote_domain, bind->remote_port, NULL,
432273474Sroyger		    NULL, NULL, 0, &evtchn->handle);
433273474Sroyger		if (error != 0) {
434273474Sroyger			free(evtchn, M_EVTCHN);
435273474Sroyger			break;
436273474Sroyger		}
437273474Sroyger		error = evtchn_bind_user_port(u, evtchn);
438273474Sroyger		if (error != 0)
439273474Sroyger			break;
440273474Sroyger		bind->port = evtchn->port;
441273474Sroyger		break;
442273474Sroyger	}
443273474Sroyger
444273474Sroyger	case IOCTL_EVTCHN_BIND_UNBOUND_PORT: {
445273474Sroyger		struct ioctl_evtchn_bind_unbound_port *bind;
446273474Sroyger		struct user_evtchn *evtchn;
447273474Sroyger
448273474Sroyger		evtchn = malloc(sizeof(*evtchn), M_EVTCHN, M_WAITOK | M_ZERO);
449273474Sroyger
450273474Sroyger		bind = (struct ioctl_evtchn_bind_unbound_port *)arg;
451273474Sroyger
452273474Sroyger		error = xen_intr_alloc_and_bind_local_port(evtchn_dev,
453273474Sroyger		    bind->remote_domain, NULL, NULL, NULL, 0, &evtchn->handle);
454273474Sroyger		if (error != 0) {
455273474Sroyger			free(evtchn, M_EVTCHN);
456273474Sroyger			break;
457273474Sroyger		}
458273474Sroyger		error = evtchn_bind_user_port(u, evtchn);
459273474Sroyger		if (error != 0)
460273474Sroyger			break;
461273474Sroyger		bind->port = evtchn->port;
462273474Sroyger		break;
463273474Sroyger	}
464273474Sroyger
465273474Sroyger	case IOCTL_EVTCHN_UNBIND: {
466273474Sroyger		struct ioctl_evtchn_unbind *unbind;
467273474Sroyger		struct user_evtchn *evtchn;
468273474Sroyger
469273474Sroyger		unbind = (struct ioctl_evtchn_unbind *)arg;
470273474Sroyger
471273474Sroyger		mtx_lock(&u->bind_mutex);
472273474Sroyger		evtchn = find_evtchn(u, unbind->port);
473273474Sroyger		if (evtchn == NULL) {
474273474Sroyger			error = ENOTCONN;
475273474Sroyger			break;
476273474Sroyger		}
477273474Sroyger
478273474Sroyger		xen_intr_unbind(&evtchn->handle);
479273474Sroyger		RB_REMOVE(evtchn_tree, &u->evtchns, evtchn);
480273474Sroyger		mtx_unlock(&u->bind_mutex);
481273474Sroyger		free(evtchn, M_EVTCHN);
482273474Sroyger		error = 0;
483273474Sroyger		break;
484273474Sroyger	}
485273474Sroyger
486273474Sroyger	case IOCTL_EVTCHN_NOTIFY: {
487273474Sroyger		struct ioctl_evtchn_notify *notify;
488273474Sroyger		struct user_evtchn *evtchn;
489273474Sroyger
490273474Sroyger		notify = (struct ioctl_evtchn_notify *)arg;
491273474Sroyger
492273474Sroyger		mtx_lock(&u->bind_mutex);
493273474Sroyger		evtchn = find_evtchn(u, notify->port);
494273474Sroyger		if (evtchn == NULL) {
495273474Sroyger			error = ENOTCONN;
496273474Sroyger			break;
497273474Sroyger		}
498273474Sroyger
499273474Sroyger		xen_intr_signal(evtchn->handle);
500273474Sroyger		mtx_unlock(&u->bind_mutex);
501273474Sroyger		error = 0;
502273474Sroyger		break;
503273474Sroyger	}
504273474Sroyger
505273474Sroyger	case IOCTL_EVTCHN_RESET: {
506273474Sroyger		/* Initialise the ring to empty. Clear errors. */
507273474Sroyger		sx_xlock(&u->ring_cons_mutex);
508273474Sroyger		mtx_lock(&u->ring_prod_mutex);
509273474Sroyger		u->ring_cons = u->ring_prod = u->ring_overflow = 0;
510273474Sroyger		mtx_unlock(&u->ring_prod_mutex);
511273474Sroyger		sx_xunlock(&u->ring_cons_mutex);
512273474Sroyger		error = 0;
513273474Sroyger		break;
514273474Sroyger	}
515273474Sroyger
516273474Sroyger	case FIONBIO:
517273474Sroyger	case FIOASYNC:
518273474Sroyger		/* Handled in an upper layer */
519273474Sroyger		error = 0;
520273474Sroyger		break;
521273474Sroyger
522273474Sroyger	default:
523273474Sroyger		error = ENOTTY;
524273474Sroyger		break;
525273474Sroyger	}
526273474Sroyger
527273474Sroyger	return (error);
528273474Sroyger}
529273474Sroyger
530273474Sroygerstatic int
531273474Sroygerevtchn_poll(struct cdev *dev, int events, struct thread *td)
532273474Sroyger{
533273474Sroyger	struct per_user_data *u;
534273474Sroyger	int error, mask;
535273474Sroyger
536273474Sroyger	error = devfs_get_cdevpriv((void **)&u);
537273474Sroyger	if (error != 0)
538273474Sroyger		return (POLLERR);
539273474Sroyger
540273474Sroyger	/* we can always write */
541273474Sroyger	mask = events & (POLLOUT | POLLWRNORM);
542273474Sroyger
543273474Sroyger	mtx_lock(&u->ring_prod_mutex);
544273474Sroyger	if (events & (POLLIN | POLLRDNORM)) {
545273474Sroyger		if (u->ring_cons != u->ring_prod) {
546273474Sroyger			mask |= events & (POLLIN | POLLRDNORM);
547273474Sroyger		} else {
548273474Sroyger			/* Record that someone is waiting */
549273474Sroyger			selrecord(td, &u->ev_rsel);
550273474Sroyger		}
551273474Sroyger	}
552273474Sroyger	mtx_unlock(&u->ring_prod_mutex);
553273474Sroyger
554273474Sroyger	return (mask);
555273474Sroyger}
556273474Sroyger
557273474Sroyger/*------------------ Private Device Attachment Functions  --------------------*/
558273474Sroygerstatic void
559273474Sroygerevtchn_identify(driver_t *driver, device_t parent)
560273474Sroyger{
561273474Sroyger
562273474Sroyger	KASSERT((xen_domain()),
563273474Sroyger	    ("Trying to attach evtchn device on non Xen domain"));
564273474Sroyger
565273474Sroyger	evtchn_dev = BUS_ADD_CHILD(parent, 0, "evtchn", 0);
566273474Sroyger	if (evtchn_dev == NULL)
567273474Sroyger		panic("unable to attach evtchn user-space device");
568273474Sroyger}
569273474Sroyger
570273474Sroygerstatic int
571273474Sroygerevtchn_probe(device_t dev)
572273474Sroyger{
573273474Sroyger
574273474Sroyger	device_set_desc(dev, "Xen event channel user-space device");
575273474Sroyger	return (BUS_PROBE_NOWILDCARD);
576273474Sroyger}
577273474Sroyger
578273474Sroygerstatic int
579273474Sroygerevtchn_attach(device_t dev)
580273474Sroyger{
581273474Sroyger
582273474Sroyger	make_dev_credf(MAKEDEV_ETERNAL, &evtchn_devsw, 0, NULL, UID_ROOT,
583273474Sroyger	    GID_WHEEL, 0600, "xen/evtchn");
584273474Sroyger	return (0);
585273474Sroyger}
586273474Sroyger
587273474Sroyger/*-------------------- Private Device Attachment Data  -----------------------*/
588273474Sroygerstatic device_method_t evtchn_methods[] = {
589273474Sroyger	DEVMETHOD(device_identify, evtchn_identify),
590273474Sroyger	DEVMETHOD(device_probe, evtchn_probe),
591273474Sroyger	DEVMETHOD(device_attach, evtchn_attach),
592273474Sroyger
593273474Sroyger	DEVMETHOD_END
594273474Sroyger};
595273474Sroyger
596273474Sroygerstatic driver_t evtchn_driver = {
597273474Sroyger	"evtchn",
598273474Sroyger	evtchn_methods,
599273474Sroyger	0,
600273474Sroyger};
601273474Sroyger
602273474Sroygerdevclass_t evtchn_devclass;
603273474Sroyger
604273474SroygerDRIVER_MODULE(evtchn, xenpv, evtchn_driver, evtchn_devclass, 0, 0);
605273474SroygerMODULE_DEPEND(evtchn, xenpv, 1, 1, 1);
606