The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/xen/evtchn/evtchn_dev.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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: releng/9.1/sys/xen/evtchn/evtchn_dev.c 204159 2010-02-21 01:12:18Z kmacy $");
   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 

Cache object: fdbb0e406bee9f7bf51c68ef03f22da1


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.