]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - sys/xen/evtchn/evtchn_dev.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / sys / xen / evtchn / evtchn_dev.c
1 /******************************************************************************
2  * evtchn.c
3  * 
4  * Xenolinux driver for receiving and demuxing event-channel signals.
5  * 
6  * Copyright (c) 2004, K A Fraser
7  */
8
9 #include <sys/cdefs.h>
10 __FBSDID("$FreeBSD$");
11
12 #include <sys/param.h>
13 #include <sys/systm.h>
14 #include <sys/uio.h>
15 #include <sys/bus.h>
16 #include <sys/malloc.h>
17 #include <sys/kernel.h>
18 #include <sys/lock.h>
19 #include <sys/mutex.h>
20 #include <sys/selinfo.h>
21 #include <sys/poll.h>
22 #include <sys/conf.h>
23 #include <sys/fcntl.h>
24 #include <sys/ioccom.h>
25
26 #include <machine/xen/xen-os.h>
27 #include <xen/xen_intr.h>
28 #include <machine/bus.h>
29 #include <sys/rman.h>
30 #include <machine/resource.h>
31 #include <machine/xen/synch_bitops.h>
32 #include <xen/hypervisor.h>
33 #include <xen/evtchn.h>
34
35
36 typedef struct evtchn_sotfc {
37
38         struct selinfo  ev_rsel;
39 } evtchn_softc_t;
40
41
42 #ifdef linuxcrap
43 /* NB. This must be shared amongst drivers if more things go in /dev/xen */
44 static devfs_handle_t xen_dev_dir;
45 #endif
46
47 /* Only one process may open /dev/xen/evtchn at any time. */
48 static unsigned long evtchn_dev_inuse;
49
50 /* Notification ring, accessed via /dev/xen/evtchn. */
51
52 #define EVTCHN_RING_SIZE     2048  /* 2048 16-bit entries */
53
54 #define EVTCHN_RING_MASK(_i) ((_i)&(EVTCHN_RING_SIZE-1))
55 static uint16_t *ring;
56 static unsigned int ring_cons, ring_prod, ring_overflow;
57
58 /* Which ports is user-space bound to? */
59 static uint32_t bound_ports[32];
60
61 /* Unique address for processes to sleep on */
62 static void *evtchn_waddr = &ring;
63
64 static struct mtx lock, upcall_lock;
65
66 static d_read_t      evtchn_read;
67 static d_write_t     evtchn_write;
68 static d_ioctl_t     evtchn_ioctl;
69 static d_poll_t      evtchn_poll;
70 static d_open_t      evtchn_open;
71 static d_close_t     evtchn_close;
72
73
74 void 
75 evtchn_device_upcall(int port)
76 {
77         mtx_lock(&upcall_lock);
78
79         mask_evtchn(port);
80         clear_evtchn(port);
81
82         if ( ring != NULL ) {
83                 if ( (ring_prod - ring_cons) < EVTCHN_RING_SIZE ) {
84                         ring[EVTCHN_RING_MASK(ring_prod)] = (uint16_t)port;
85                         if ( ring_cons == ring_prod++ ) {
86                                 wakeup(evtchn_waddr);
87                         }
88                 }
89                 else {
90                         ring_overflow = 1;
91                 }
92         }
93
94         mtx_unlock(&upcall_lock);
95 }
96
97 static void 
98 __evtchn_reset_buffer_ring(void)
99 {
100         /* Initialise the ring to empty. Clear errors. */
101         ring_cons = ring_prod = ring_overflow = 0;
102 }
103
104 static int
105 evtchn_read(struct cdev *dev, struct uio *uio, int ioflag)
106 {
107         int rc;
108         unsigned int count, c, p, sst = 0, bytes1 = 0, bytes2 = 0;
109         count = uio->uio_resid;
110     
111         count &= ~1; /* even number of bytes */
112
113         if ( count == 0 )
114         {
115                 rc = 0;
116                 goto out;
117         }
118
119         if ( count > PAGE_SIZE )
120                 count = PAGE_SIZE;
121
122         for ( ; ; ) {
123                 if ( (c = ring_cons) != (p = ring_prod) )
124                         break;
125
126                 if ( ring_overflow ) {
127                         rc = EFBIG;
128                         goto out;
129                 }
130
131                 if (sst != 0) {
132                         rc = EINTR;
133                         goto out;
134                 }
135
136                 /* PCATCH == check for signals before and after sleeping 
137                  * PWAIT == priority of waiting on resource 
138                  */
139                 sst = tsleep(evtchn_waddr, PWAIT|PCATCH, "evchwt", 10);
140         }
141
142         /* Byte lengths of two chunks. Chunk split (if any) is at ring wrap. */
143         if ( ((c ^ p) & EVTCHN_RING_SIZE) != 0 ) {
144                 bytes1 = (EVTCHN_RING_SIZE - EVTCHN_RING_MASK(c)) * sizeof(uint16_t);
145                 bytes2 = EVTCHN_RING_MASK(p) * sizeof(uint16_t);
146         }
147         else {
148                 bytes1 = (p - c) * sizeof(uint16_t);
149                 bytes2 = 0;
150         }
151
152         /* Truncate chunks according to caller's maximum byte count. */
153         if ( bytes1 > count ) {
154                 bytes1 = count;
155                 bytes2 = 0;
156         }
157         else if ( (bytes1 + bytes2) > count ) {
158                 bytes2 = count - bytes1;
159         }
160     
161         if ( uiomove(&ring[EVTCHN_RING_MASK(c)], bytes1, uio) ||
162              ((bytes2 != 0) && uiomove(&ring[0], bytes2, uio)))
163                 /* keeping this around as its replacement is not equivalent 
164                  * copyout(&ring[0], &buf[bytes1], bytes2) 
165                  */
166         {
167                 rc = EFAULT;
168                 goto out;
169         }
170
171         ring_cons += (bytes1 + bytes2) / sizeof(uint16_t);
172
173         rc = bytes1 + bytes2;
174
175  out:
176     
177         return rc;
178 }
179
180 static int 
181 evtchn_write(struct cdev *dev, struct uio *uio, int ioflag)
182 {
183         int  rc, i, count;
184     
185         count = uio->uio_resid;
186     
187         uint16_t *kbuf = (uint16_t *)malloc(PAGE_SIZE, M_DEVBUF, M_WAITOK);
188
189
190         if ( kbuf == NULL )
191                 return ENOMEM;
192
193         count &= ~1; /* even number of bytes */
194
195         if ( count == 0 ) {
196                 rc = 0;
197                 goto out;
198         }
199
200         if ( count > PAGE_SIZE )
201                 count = PAGE_SIZE;
202
203         if ( uiomove(kbuf, count, uio) != 0 ) {
204                 rc = EFAULT;
205                 goto out;
206         }
207
208         mtx_lock_spin(&lock);
209         for ( i = 0; i < (count/2); i++ )
210                 if ( test_bit(kbuf[i], &bound_ports[0]) )
211                         unmask_evtchn(kbuf[i]);
212         mtx_unlock_spin(&lock);
213
214         rc = count;
215
216  out:
217         free(kbuf, M_DEVBUF);
218         return rc;
219 }
220
221 static int 
222 evtchn_ioctl(struct cdev *dev, unsigned long cmd, caddr_t arg, 
223              int mode, struct thread *td __unused)
224 {
225         int rc = 0;
226     
227         mtx_lock_spin(&lock);
228     
229         switch ( cmd )
230         {
231         case EVTCHN_RESET:
232                 __evtchn_reset_buffer_ring();
233                 break;
234         case EVTCHN_BIND:
235                 if ( !synch_test_and_set_bit((uintptr_t)arg, &bound_ports[0]) )
236                         unmask_evtchn((uintptr_t)arg);
237                 else
238                         rc = EINVAL;
239                 break;
240         case EVTCHN_UNBIND:
241                 if ( synch_test_and_clear_bit((uintptr_t)arg, &bound_ports[0]) )
242                         mask_evtchn((uintptr_t)arg);
243                 else
244                         rc = EINVAL;
245                 break;
246         default:
247                 rc = ENOSYS;
248                 break;
249         }
250
251         mtx_unlock_spin(&lock);   
252
253         return rc;
254 }
255
256 static int
257 evtchn_poll(struct cdev *dev, int poll_events, struct thread *td)
258 {
259
260         evtchn_softc_t *sc;
261         unsigned int mask = POLLOUT | POLLWRNORM;
262     
263         sc = dev->si_drv1;
264     
265         if ( ring_cons != ring_prod )
266                 mask |= POLLIN | POLLRDNORM;
267         else if ( ring_overflow )
268                 mask = POLLERR;
269         else
270                 selrecord(td, &sc->ev_rsel);
271
272
273         return mask;
274 }
275
276
277 static int 
278 evtchn_open(struct cdev *dev, int flag, int otyp, struct thread *td)
279 {
280         uint16_t *_ring;
281     
282         if (flag & O_NONBLOCK)
283                 return EBUSY;
284
285         if ( synch_test_and_set_bit(0, &evtchn_dev_inuse) )
286                 return EBUSY;
287
288         if ( (_ring = (uint16_t *)malloc(PAGE_SIZE, M_DEVBUF, M_WAITOK)) == NULL )
289                 return ENOMEM;
290
291         mtx_lock_spin(&lock);
292         ring = _ring;
293         __evtchn_reset_buffer_ring();
294         mtx_unlock_spin(&lock);
295
296
297         return 0;
298 }
299
300 static int 
301 evtchn_close(struct cdev *dev, int flag, int otyp, struct thread *td __unused)
302 {
303         int i;
304
305         if (ring != NULL) {
306                 free(ring, M_DEVBUF);
307                 ring = NULL;
308         }
309         mtx_lock_spin(&lock);
310         for ( i = 0; i < NR_EVENT_CHANNELS; i++ )
311                 if ( synch_test_and_clear_bit(i, &bound_ports[0]) )
312                         mask_evtchn(i);
313         mtx_unlock_spin(&lock);
314
315         evtchn_dev_inuse = 0;
316
317         return 0;
318 }
319
320 static struct cdevsw evtchn_devsw = {
321         d_version:   D_VERSION,
322         d_open:      evtchn_open,
323         d_close:     evtchn_close,
324         d_read:      evtchn_read,
325         d_write:     evtchn_write,
326         d_ioctl:     evtchn_ioctl,
327         d_poll:      evtchn_poll,
328         d_name:      "evtchn",
329         d_flags:     0,
330 };
331
332
333 /* XXX  - if this device is ever supposed to support use by more than one process
334  * this global static will have to go away
335  */
336 static struct cdev *evtchn_dev;
337
338
339
340 static int 
341 evtchn_dev_init(void *dummy __unused)
342 {
343         /* XXX I believe we don't need these leaving them here for now until we 
344          * have some semblance of it working 
345          */
346         mtx_init(&upcall_lock, "evtchup", NULL, MTX_DEF);
347
348         /* (DEVFS) create '/dev/misc/evtchn'. */
349         evtchn_dev = make_dev(&evtchn_devsw, 0, UID_ROOT, GID_WHEEL, 0600, "xen/evtchn");
350
351         mtx_init(&lock, "evch", NULL, MTX_SPIN | MTX_NOWITNESS);
352
353         evtchn_dev->si_drv1 = malloc(sizeof(evtchn_softc_t), M_DEVBUF, M_WAITOK);
354         bzero(evtchn_dev->si_drv1, sizeof(evtchn_softc_t));
355
356         /* XXX I don't think we need any of this rubbish */
357 #if 0
358         if ( err != 0 )
359         {
360                 printk(KERN_ALERT "Could not register /dev/misc/evtchn\n");
361                 return err;
362         }
363
364         /* (DEVFS) create directory '/dev/xen'. */
365         xen_dev_dir = devfs_mk_dir(NULL, "xen", NULL);
366
367         /* (DEVFS) &link_dest[pos] == '../misc/evtchn'. */
368         pos = devfs_generate_path(evtchn_miscdev.devfs_handle, 
369                                   &link_dest[3], 
370                                   sizeof(link_dest) - 3);
371         if ( pos >= 0 )
372                 strncpy(&link_dest[pos], "../", 3);
373         /* (DEVFS) symlink '/dev/xen/evtchn' -> '../misc/evtchn'. */
374         (void)devfs_mk_symlink(xen_dev_dir, 
375                                "evtchn", 
376                                DEVFS_FL_DEFAULT, 
377                                &link_dest[pos],
378                                &symlink_handle, 
379                                NULL);
380
381         /* (DEVFS) automatically destroy the symlink with its destination. */
382         devfs_auto_unregister(evtchn_miscdev.devfs_handle, symlink_handle);
383 #endif
384         if (bootverbose)
385                 printf("Event-channel device installed.\n");
386
387         return 0;
388 }
389
390 SYSINIT(evtchn_dev_init, SI_SUB_DRIVERS, SI_ORDER_FIRST, evtchn_dev_init, NULL);
391
392