ia64/xen-unstable

changeset 1135:ca5de6ca0355

bitkeeper revision 1.757 (40422543Wg1i77yDldDqmAGZ6DVnnQ)

xl_evtchn.c, event_channel.h, event_channel.c, Xc.c, xc.h:
Cleanups and fixes for event channels.
author kaf24@scramble.cl.cam.ac.uk
date Sun Feb 29 17:45:39 2004 +0000 (2004-02-29)
parents c71a42306245
children 1d81002643e4
files tools/xc/lib/xc.h tools/xc/py/Xc.c xen/common/event_channel.c xen/include/hypervisor-ifs/event_channel.h xenolinux-2.4.25-sparse/arch/xeno/drivers/evtchn/xl_evtchn.c
line diff
     1.1 --- a/tools/xc/lib/xc.h	Sun Feb 29 15:51:23 2004 +0000
     1.2 +++ b/tools/xc/lib/xc.h	Sun Feb 29 17:45:39 2004 +0000
     1.3 @@ -162,7 +162,7 @@ int xc_vbd_probe(int xc_handle,
     1.4  #define EVTCHNSTAT_connected    2  /* Channel is connected to remote.     */
     1.5  int xc_evtchn_open(int xc_handle,
     1.6                     u64 dom1,   /* may be DOMID_SELF */
     1.7 -                   u64 dom2,
     1.8 +                   u64 dom2,   /* may be DOMID_SELF */
     1.9                     int *port1,
    1.10                     int *port2);
    1.11  int xc_evtchn_close(int xc_handle,
     2.1 --- a/tools/xc/py/Xc.c	Sun Feb 29 15:51:23 2004 +0000
     2.2 +++ b/tools/xc/py/Xc.c	Sun Feb 29 17:45:39 2004 +0000
     2.3 @@ -772,13 +772,13 @@ static PyObject *pyxc_evtchn_open(PyObje
     2.4      XcObject *xc = (XcObject *)self;
     2.5      PyObject *dict;
     2.6  
     2.7 -    u64 dom1 = DOMID_SELF, dom2;
     2.8 +    u64 dom1 = DOMID_SELF, dom2 = DOMID_SELF;
     2.9      int port1, port2, ret;
    2.10  
    2.11 -    static char *kwd_list[] = { "dom2", "dom1", NULL };
    2.12 +    static char *kwd_list[] = { "dom1", "dom2", NULL };
    2.13  
    2.14 -    if ( !PyArg_ParseTupleAndKeywords(args, kwds, "L|L", kwd_list, 
    2.15 -                                      &dom2, &dom1) )
    2.16 +    if ( !PyArg_ParseTupleAndKeywords(args, kwds, "|LL", kwd_list, 
    2.17 +                                      &dom1, &dom2) )
    2.18      {
    2.19          DPRINTF("could not parse parameter list.");
    2.20          return NULL;
    2.21 @@ -1163,7 +1163,7 @@ static PyMethodDef pyxc_methods[] = {
    2.22        METH_VARARGS | METH_KEYWORDS, "\n"
    2.23        "Open an event channel between two domains.\n"
    2.24        " dom1 [long, SELF]: First domain to be connected.\n"
    2.25 -      " dom2 [long]:       Second domain to be connected.\n\n"
    2.26 +      " dom2 [long, SELF]: Second domain to be connected.\n\n"
    2.27        "Returns: [dict] dictionary is empty on failure.\n"
    2.28        " port1 [int]: Port-id for endpoint at dom1.\n"
    2.29        " port2 [int]: Port-id for endpoint at dom2.\n" },
     3.1 --- a/xen/common/event_channel.c	Sun Feb 29 15:51:23 2004 +0000
     3.2 +++ b/xen/common/event_channel.c	Sun Feb 29 17:45:39 2004 +0000
     3.3 @@ -92,15 +92,10 @@ static long event_channel_open(evtchn_op
     3.4      if ( !IS_PRIV(current) )
     3.5          return -EPERM;
     3.6  
     3.7 -    /* 'dom1' may be DOMID_SELF. 'dom2' cannot be.*/
     3.8      if ( dom1 == DOMID_SELF )
     3.9          dom1 = current->domain;
    3.10      if ( dom2 == DOMID_SELF )
    3.11 -        return -EINVAL;
    3.12 -
    3.13 -    /* Event channel must connect distinct domains. */
    3.14 -    if ( dom1 == dom2 )
    3.15 -        return -EINVAL;
    3.16 +        dom2 = current->domain;
    3.17  
    3.18      if ( ((p1 = find_domain_by_id(dom1)) == NULL) ||
    3.19           ((p2 = find_domain_by_id(dom2)) == NULL) )
    3.20 @@ -118,7 +113,8 @@ static long event_channel_open(evtchn_op
    3.21      }
    3.22      else
    3.23      {
    3.24 -        spin_lock(&p2->event_channel_lock);
    3.25 +        if ( p1 != p2 )
    3.26 +            spin_lock(&p2->event_channel_lock);
    3.27          spin_lock(&p1->event_channel_lock);
    3.28      }
    3.29  
    3.30 @@ -148,7 +144,8 @@ static long event_channel_open(evtchn_op
    3.31      
    3.32   out:
    3.33      spin_unlock(&p1->event_channel_lock);
    3.34 -    spin_unlock(&p2->event_channel_lock);
    3.35 +    if ( p1 != p2 )
    3.36 +        spin_unlock(&p2->event_channel_lock);
    3.37      
    3.38      put_task_struct(p1);
    3.39      put_task_struct(p2);
    3.40 @@ -191,7 +188,7 @@ static long __event_channel_close(struct
    3.41              {
    3.42                  spin_lock(&p2->event_channel_lock);
    3.43              }
    3.44 -            else
    3.45 +            else if ( p1 != p2 )
    3.46              {
    3.47                  spin_unlock(&p1->event_channel_lock);
    3.48                  spin_lock(&p2->event_channel_lock);
    3.49 @@ -234,7 +231,8 @@ static long __event_channel_close(struct
    3.50  
    3.51      if ( p2 != NULL )
    3.52      {
    3.53 -        spin_unlock(&p2->event_channel_lock);
    3.54 +        if ( p1 != p2 )
    3.55 +            spin_unlock(&p2->event_channel_lock);
    3.56          put_task_struct(p2);
    3.57      }
    3.58      
     4.1 --- a/xen/include/hypervisor-ifs/event_channel.h	Sun Feb 29 15:51:23 2004 +0000
     4.2 +++ b/xen/include/hypervisor-ifs/event_channel.h	Sun Feb 29 17:45:39 2004 +0000
     4.3 @@ -12,7 +12,7 @@
     4.4  /*
     4.5   * EVTCHNOP_open: Open a communication channel between <dom1> and <dom2>.
     4.6   * NOTES:
     4.7 - *  1. <dom1> may be specified as DOMID_SELF.
     4.8 + *  1. <dom1> and/or <dom2> may be specified as DOMID_SELF.
     4.9   *  2. Only a sufficiently-privileged domain may create an event channel.
    4.10   *  3. <port1> and <port2> are only supplied if the op succeeds.
    4.11   */
     5.1 --- a/xenolinux-2.4.25-sparse/arch/xeno/drivers/evtchn/xl_evtchn.c	Sun Feb 29 15:51:23 2004 +0000
     5.2 +++ b/xenolinux-2.4.25-sparse/arch/xeno/drivers/evtchn/xl_evtchn.c	Sun Feb 29 17:45:39 2004 +0000
     5.3 @@ -30,6 +30,10 @@ typedef void (*evtchn_receiver_t)(unsign
     5.4  /* /dev/xeno/evtchn resides at device number major=10, minor=200 */
     5.5  #define EVTCHN_MINOR 200
     5.6  
     5.7 +/* /dev/xeno/evtchn ioctls: */
     5.8 +/* EVTCHN_RESET: Clear and reinit the event buffer. Clear error condition. */
     5.9 +#define EVTCHN_RESET _IO('E', 1)
    5.10 +
    5.11  /* NB. This must be shared amongst drivers if more things go in /dev/xeno */
    5.12  static devfs_handle_t xeno_dev_dir;
    5.13  
    5.14 @@ -37,8 +41,10 @@ static devfs_handle_t xeno_dev_dir;
    5.15  static unsigned long evtchn_dev_inuse;
    5.16  
    5.17  /* Notification ring, accessed via /dev/xeno/evtchn. */
    5.18 +#define RING_SIZE     2048  /* 2048 16-bit entries */
    5.19 +#define RING_MASK(_i) ((_i)&(RING_SIZE-1))
    5.20  static u16 *ring;
    5.21 -static unsigned int ring_cons, ring_prod;
    5.22 +static unsigned int ring_cons, ring_prod, ring_overflow;
    5.23  
    5.24  /* Processes wait on this queue via /dev/xeno/evtchn when ring is empty. */
    5.25  static DECLARE_WAIT_QUEUE_HEAD(evtchn_wait);
    5.26 @@ -146,11 +152,18 @@ static inline void process_bitmask(u32 *
    5.27              }
    5.28              else if ( ring != NULL )
    5.29              {
    5.30 -                ring[ring_prod] = (u16)(port | port_subtype);
    5.31 -                if ( ring_cons == ring_prod++ )
    5.32 +                if ( (ring_prod - ring_cons) < RING_SIZE )
    5.33                  {
    5.34 -                    wake_up_interruptible(&evtchn_wait);
    5.35 -                    kill_fasync(&evtchn_async_queue, SIGIO, POLL_IN);
    5.36 +                    ring[RING_MASK(ring_prod)] = (u16)(port | port_subtype);
    5.37 +                    if ( ring_cons == ring_prod++ )
    5.38 +                    {
    5.39 +                        wake_up_interruptible(&evtchn_wait);
    5.40 +                        kill_fasync(&evtchn_async_queue, SIGIO, POLL_IN);
    5.41 +                    }
    5.42 +                }
    5.43 +                else
    5.44 +                {
    5.45 +                    ring_overflow = 1;
    5.46                  }
    5.47              }
    5.48          }
    5.49 @@ -178,116 +191,14 @@ static void evtchn_interrupt(int irq, vo
    5.50      spin_unlock_irqrestore(&lock, flags);
    5.51  }
    5.52  
    5.53 -static ssize_t evtchn_read(struct file *file, char *buf,
    5.54 -                           size_t count, loff_t *ppos)
    5.55 -{
    5.56 -    int rc;
    5.57 -    DECLARE_WAITQUEUE(wait, current);
    5.58 -
    5.59 -    add_wait_queue(&evtchn_wait, &wait);
    5.60 -
    5.61 -    for ( ; ; )
    5.62 -    {
    5.63 -        set_current_state(TASK_INTERRUPTIBLE);
    5.64 -
    5.65 -        if ( ring_cons != ring_prod )
    5.66 -            break;
    5.67 -
    5.68 -        if ( file->f_flags & O_NONBLOCK )
    5.69 -        {
    5.70 -            rc = -EAGAIN;
    5.71 -            goto out;
    5.72 -        }
    5.73 -
    5.74 -        if ( signal_pending(current) )
    5.75 -        {
    5.76 -            rc = -ERESTARTSYS;
    5.77 -            goto out;
    5.78 -        }
    5.79 -
    5.80 -        schedule();
    5.81 -    }
    5.82 -
    5.83 -    rc = -EINVAL;
    5.84 -    if ( count >= sizeof(ring_prod) )
    5.85 -        rc = put_user(ring_prod, (unsigned int *)buf);
    5.86 -    if ( rc == 0 )
    5.87 -        rc = sizeof(ring_prod);
    5.88 -
    5.89 - out:
    5.90 -    __set_current_state(TASK_RUNNING);
    5.91 -    remove_wait_queue(&evtchn_wait, &wait);
    5.92 -    return rc;
    5.93 -}
    5.94 -
    5.95 -static ssize_t evtchn_write(struct file *file, const char *buf,
    5.96 -                            size_t count, loff_t *ppos)
    5.97 +static void __evtchn_reset_buffer_ring(void)
    5.98  {
    5.99 -    int          rc = -EINVAL;
   5.100 -    unsigned int new_cons = 0;
   5.101 -
   5.102 -    if ( count >= sizeof(new_cons) )
   5.103 -        rc = get_user(new_cons, (unsigned int *)buf);
   5.104 -
   5.105 -    if ( rc != 0 )
   5.106 -        return rc;
   5.107 -
   5.108 -    rc = sizeof(new_cons);
   5.109 -
   5.110 -    while ( ring_cons != new_cons )
   5.111 -        evtchn_clear_port(ring[ring_cons++]);
   5.112 -
   5.113 -    return rc;
   5.114 -}
   5.115 -
   5.116 -static unsigned int evtchn_poll(struct file *file, poll_table *wait)
   5.117 -{
   5.118 -    unsigned int mask = POLLOUT | POLLWRNORM;
   5.119 -    poll_wait(file, &evtchn_wait, wait);
   5.120 -    if ( ring_cons != ring_prod )
   5.121 -        mask |= POLLIN | POLLRDNORM;
   5.122 -    return mask;
   5.123 -}
   5.124 -
   5.125 -static int evtchn_mmap(struct file *file, struct vm_area_struct *vma)
   5.126 -{
   5.127 -    /* Caller must map a single page of memory from 'file offset' zero. */
   5.128 -    if ( (vma->vm_pgoff != 0) || ((vma->vm_end - vma->vm_start) != PAGE_SIZE) )
   5.129 -        return -EINVAL;
   5.130 -
   5.131 -    /* Not a pageable area. */
   5.132 -    vma->vm_flags |= VM_RESERVED;
   5.133 -
   5.134 -    if ( remap_page_range(vma->vm_start, 0, PAGE_SIZE, vma->vm_page_prot) )
   5.135 -        return -EAGAIN;
   5.136 -
   5.137 -    return 0;
   5.138 -}
   5.139 -
   5.140 -static int evtchn_fasync(int fd, struct file *filp, int on)
   5.141 -{
   5.142 -    return fasync_helper(fd, filp, on, &evtchn_async_queue);
   5.143 -}
   5.144 -
   5.145 -static int evtchn_open(struct inode *inode, struct file *filp)
   5.146 -{
   5.147 -    u16         *_ring;
   5.148      u32          m;
   5.149      unsigned int i, j;
   5.150  
   5.151 -    if ( test_and_set_bit(0, &evtchn_dev_inuse) )
   5.152 -        return -EBUSY;
   5.153 -
   5.154 -    /* Allocate outside locked region so that we can use GFP_KERNEL. */
   5.155 -    if ( (_ring = (u16 *)get_free_page(GFP_KERNEL)) == NULL )
   5.156 -        return -ENOMEM;
   5.157 +    /* Initialise the ring with currently outstanding notifications. */
   5.158 +    ring_cons = ring_prod = ring_overflow = 0;
   5.159  
   5.160 -    spin_lock_irq(&lock);
   5.161 -
   5.162 -    ring = _ring;
   5.163 -
   5.164 -    /* Initialise the ring with currently outstanding notifications. */
   5.165 -    ring_cons = ring_prod = 0;
   5.166      for ( i = 0; i < 32; i++ )
   5.167      {
   5.168          m = pend_outstanding[i];
   5.169 @@ -306,7 +217,161 @@ static int evtchn_open(struct inode *ino
   5.170                  ring[ring_prod++] = (u16)(((i * 32) + j) | PORT_DISCONNECT);
   5.171          }
   5.172      }
   5.173 +}
   5.174  
   5.175 +static ssize_t evtchn_read(struct file *file, char *buf,
   5.176 +                           size_t count, loff_t *ppos)
   5.177 +{
   5.178 +    int rc;
   5.179 +    unsigned int c, p, bytes1 = 0, bytes2 = 0;
   5.180 +    DECLARE_WAITQUEUE(wait, current);
   5.181 +
   5.182 +    add_wait_queue(&evtchn_wait, &wait);
   5.183 +
   5.184 +    if ( (count <= 0) || (count > PAGE_SIZE) || ((count&1) != 0) )
   5.185 +    {
   5.186 +        rc = -EINVAL;
   5.187 +        goto out;
   5.188 +    }
   5.189 +
   5.190 +    for ( ; ; )
   5.191 +    {
   5.192 +        set_current_state(TASK_INTERRUPTIBLE);
   5.193 +
   5.194 +        if ( (c = ring_cons) != (p = ring_prod) )
   5.195 +            break;
   5.196 +
   5.197 +        if ( ring_overflow )
   5.198 +        {
   5.199 +            rc = -EFBIG;
   5.200 +            goto out;
   5.201 +        }
   5.202 +
   5.203 +        if ( file->f_flags & O_NONBLOCK )
   5.204 +        {
   5.205 +            rc = -EAGAIN;
   5.206 +            goto out;
   5.207 +        }
   5.208 +
   5.209 +        if ( signal_pending(current) )
   5.210 +        {
   5.211 +            rc = -ERESTARTSYS;
   5.212 +            goto out;
   5.213 +        }
   5.214 +
   5.215 +        schedule();
   5.216 +    }
   5.217 +
   5.218 +    rc = -EFAULT;
   5.219 +
   5.220 +    /* Byte length of first chunk. May be truncated by ring wrap. */
   5.221 +    if ( ((c ^ p) & RING_SIZE) != 0 )
   5.222 +        bytes1 = (RING_SIZE - RING_MASK(c)) * sizeof(u16);
   5.223 +    else
   5.224 +        bytes1 = (p - c) * sizeof(u16);
   5.225 +
   5.226 +    /* Further truncate chunk length according to caller's maximum count. */
   5.227 +    if ( bytes1 > count )
   5.228 +        bytes1 = count;
   5.229 +
   5.230 +    /* Copy the first chunk. */
   5.231 +    if ( copy_to_user(buf, &ring[c], bytes1) != 0 )
   5.232 +        goto out;
   5.233 +
   5.234 +    /* More bytes to copy? */
   5.235 +    if ( count > bytes1 )
   5.236 +    {
   5.237 +        bytes2 = RING_MASK(p) * sizeof(u16);
   5.238 +        if ( bytes2 > count )
   5.239 +            bytes2 = count;
   5.240 +        if ( (bytes2 != 0) && copy_to_user(&buf[bytes1], &ring[0], bytes2) )
   5.241 +            goto out;
   5.242 +    }
   5.243 +
   5.244 +    ring_cons = (bytes1 + bytes2) / sizeof(u16);
   5.245 +
   5.246 +    rc = bytes1 + bytes2;
   5.247 +
   5.248 + out:
   5.249 +    __set_current_state(TASK_RUNNING);
   5.250 +    remove_wait_queue(&evtchn_wait, &wait);
   5.251 +    return rc;
   5.252 +}
   5.253 +
   5.254 +static ssize_t evtchn_write(struct file *file, const char *buf,
   5.255 +                            size_t count, loff_t *ppos)
   5.256 +{
   5.257 +    int  rc, i;
   5.258 +    u16 *kbuf = (u16 *)get_free_page(GFP_KERNEL);
   5.259 +
   5.260 +    if ( kbuf == NULL )
   5.261 +        return -ENOMEM;
   5.262 +
   5.263 +    if ( (count <= 0) || (count > PAGE_SIZE) || ((count&1) != 0) )
   5.264 +    {
   5.265 +        rc = -EINVAL;
   5.266 +        goto out;
   5.267 +    }
   5.268 +
   5.269 +    if ( copy_from_user(kbuf, buf, count) != 0 )
   5.270 +    {
   5.271 +        rc = -EFAULT;
   5.272 +        goto out;
   5.273 +    }
   5.274 +
   5.275 +    for ( i = 0; i < (count/2); i++ )
   5.276 +        evtchn_clear_port(kbuf[i]);
   5.277 +
   5.278 +    rc = count;
   5.279 +
   5.280 + out:
   5.281 +    free_page((unsigned long)kbuf);
   5.282 +    return rc;
   5.283 +}
   5.284 +
   5.285 +static int evtchn_ioctl(struct inode *inode, struct file *file,
   5.286 +                        unsigned int cmd, unsigned long arg)
   5.287 +{
   5.288 +    if ( cmd != EVTCHN_RESET )
   5.289 +        return -EINVAL;
   5.290 +
   5.291 +    spin_lock_irq(&lock);
   5.292 +    __evtchn_reset_buffer_ring();
   5.293 +    spin_unlock_irq(&lock);   
   5.294 +
   5.295 +    return 0;
   5.296 +}
   5.297 +
   5.298 +static unsigned int evtchn_poll(struct file *file, poll_table *wait)
   5.299 +{
   5.300 +    unsigned int mask = POLLOUT | POLLWRNORM;
   5.301 +    poll_wait(file, &evtchn_wait, wait);
   5.302 +    if ( ring_cons != ring_prod )
   5.303 +        mask |= POLLIN | POLLRDNORM;
   5.304 +    if ( ring_overflow )
   5.305 +        mask = POLLERR;
   5.306 +    return mask;
   5.307 +}
   5.308 +
   5.309 +static int evtchn_fasync(int fd, struct file *filp, int on)
   5.310 +{
   5.311 +    return fasync_helper(fd, filp, on, &evtchn_async_queue);
   5.312 +}
   5.313 +
   5.314 +static int evtchn_open(struct inode *inode, struct file *filp)
   5.315 +{
   5.316 +    u16 *_ring;
   5.317 +
   5.318 +    if ( test_and_set_bit(0, &evtchn_dev_inuse) )
   5.319 +        return -EBUSY;
   5.320 +
   5.321 +    /* Allocate outside locked region so that we can use GFP_KERNEL. */
   5.322 +    if ( (_ring = (u16 *)get_free_page(GFP_KERNEL)) == NULL )
   5.323 +        return -ENOMEM;
   5.324 +
   5.325 +    spin_lock_irq(&lock);
   5.326 +    ring = _ring;
   5.327 +    __evtchn_reset_buffer_ring();
   5.328      spin_unlock_irq(&lock);
   5.329  
   5.330      MOD_INC_USE_COUNT;
   5.331 @@ -335,8 +400,8 @@ static struct file_operations evtchn_fop
   5.332      owner:    THIS_MODULE,
   5.333      read:     evtchn_read,
   5.334      write:    evtchn_write,
   5.335 +    ioctl:    evtchn_ioctl,
   5.336      poll:     evtchn_poll,
   5.337 -    mmap:     evtchn_mmap,
   5.338      fasync:   evtchn_fasync,
   5.339      open:     evtchn_open,
   5.340      release:  evtchn_release