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