ia64/xen-unstable

changeset 1134:c71a42306245

bitkeeper revision 1.756 (40420a7bDsT_OI1_rz4fkewUJosvRA)

xl_evtchn.c, Makefile:
new file
hypervisor.c, network.c, Makefile:
Event-channel demuxing in Xenolinux.
author kaf24@scramble.cl.cam.ac.uk
date Sun Feb 29 15:51:23 2004 +0000 (2004-02-29)
parents cd5a94809f8a
children ca5de6ca0355
files .rootkeys xenolinux-2.4.25-sparse/arch/xeno/Makefile xenolinux-2.4.25-sparse/arch/xeno/drivers/evtchn/Makefile xenolinux-2.4.25-sparse/arch/xeno/drivers/evtchn/xl_evtchn.c xenolinux-2.4.25-sparse/arch/xeno/drivers/network/network.c xenolinux-2.4.25-sparse/arch/xeno/kernel/hypervisor.c
line diff
     1.1 --- a/.rootkeys	Fri Feb 27 15:19:27 2004 +0000
     1.2 +++ b/.rootkeys	Sun Feb 29 15:51:23 2004 +0000
     1.3 @@ -534,6 +534,8 @@ 3e5a4e651TH-SXHoufurnWjgl5bfOA xenolinux
     1.4  3e5a4e656nfFISThfbyXQOA6HN6YHw xenolinux-2.4.25-sparse/arch/xeno/drivers/dom0/Makefile
     1.5  3e5a4e65BXtftInNHUC2PjDfPhdZZA xenolinux-2.4.25-sparse/arch/xeno/drivers/dom0/dom0_core.c
     1.6  3e5a4e65gfn_ltB8ujHMVFApnTTNRQ xenolinux-2.4.25-sparse/arch/xeno/drivers/dom0/vfr.c
     1.7 +40420a6ebRqDjufoN1WSJvolEW2Wjw xenolinux-2.4.25-sparse/arch/xeno/drivers/evtchn/Makefile
     1.8 +40420a73Wou6JlsZDiu6YwjYomsm7A xenolinux-2.4.25-sparse/arch/xeno/drivers/evtchn/xl_evtchn.c
     1.9  3e5a4e65gZBRBB6RsSVg1c9iahigAw xenolinux-2.4.25-sparse/arch/xeno/drivers/network/Makefile
    1.10  3e5a4e65ZxKrbFetVB84JhrTyZ1YuQ xenolinux-2.4.25-sparse/arch/xeno/drivers/network/network.c
    1.11  3e5a4e65lWzkiPXsZdzPt2RNnJGG1g xenolinux-2.4.25-sparse/arch/xeno/kernel/Makefile
     2.1 --- a/xenolinux-2.4.25-sparse/arch/xeno/Makefile	Fri Feb 27 15:19:27 2004 +0000
     2.2 +++ b/xenolinux-2.4.25-sparse/arch/xeno/Makefile	Sun Feb 29 15:51:23 2004 +0000
     2.3 @@ -48,7 +48,8 @@ HEAD := arch/xeno/kernel/head.o arch/xen
     2.4  
     2.5  SUBDIRS += arch/xeno/kernel arch/xeno/mm arch/xeno/lib
     2.6  SUBDIRS += arch/xeno/drivers/console arch/xeno/drivers/network
     2.7 -SUBDIRS += arch/xeno/drivers/block arch/xeno/drivers/balloon
     2.8 +SUBDIRS += arch/xeno/drivers/evtchn arch/xeno/drivers/block
     2.9 +SUBDIRS += arch/xeno/drivers/balloon
    2.10  ifdef CONFIG_XENO_PRIV
    2.11  SUBDIRS += arch/xeno/drivers/dom0 
    2.12  endif
    2.13 @@ -56,6 +57,7 @@ endif
    2.14  CORE_FILES += arch/xeno/kernel/kernel.o arch/xeno/mm/mm.o
    2.15  CORE_FILES += arch/xeno/drivers/console/con.o
    2.16  CORE_FILES += arch/xeno/drivers/block/blk.o
    2.17 +CORE_FILES += arch/xeno/drivers/evtchn/evtchn.o
    2.18  CORE_FILES += arch/xeno/drivers/network/net.o
    2.19  ifdef CONFIG_XENO_PRIV
    2.20  CORE_FILES += arch/xeno/drivers/dom0/dom0.o
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/xenolinux-2.4.25-sparse/arch/xeno/drivers/evtchn/Makefile	Sun Feb 29 15:51:23 2004 +0000
     3.3 @@ -0,0 +1,3 @@
     3.4 +O_TARGET := evtchn.o
     3.5 +obj-y := xl_evtchn.o
     3.6 +include $(TOPDIR)/Rules.make
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/xenolinux-2.4.25-sparse/arch/xeno/drivers/evtchn/xl_evtchn.c	Sun Feb 29 15:51:23 2004 +0000
     4.3 @@ -0,0 +1,403 @@
     4.4 +/******************************************************************************
     4.5 + * xl_evtchn.c
     4.6 + * 
     4.7 + * Xenolinux driver for receiving and demuxing event-channel signals.
     4.8 + * 
     4.9 + * Copyright (c) 2004, K A Fraser
    4.10 + */
    4.11 +
    4.12 +#include <linux/config.h>
    4.13 +#include <linux/module.h>
    4.14 +#include <linux/kernel.h>
    4.15 +#include <linux/sched.h>
    4.16 +#include <linux/slab.h>
    4.17 +#include <linux/string.h>
    4.18 +#include <linux/errno.h>
    4.19 +#include <linux/fs.h>
    4.20 +#include <linux/errno.h>
    4.21 +#include <linux/miscdevice.h>
    4.22 +#include <linux/major.h>
    4.23 +#include <linux/proc_fs.h>
    4.24 +#include <linux/devfs_fs_kernel.h>
    4.25 +#include <linux/stat.h>
    4.26 +#include <linux/poll.h>
    4.27 +
    4.28 +typedef void (*evtchn_receiver_t)(unsigned int);
    4.29 +#define PORT_NORMAL     0x0000
    4.30 +#define PORT_DISCONNECT 0x8000
    4.31 +#define PORTIDX_MASK    0x7fff
    4.32 +
    4.33 +/* /dev/xeno/evtchn resides at device number major=10, minor=200 */
    4.34 +#define EVTCHN_MINOR 200
    4.35 +
    4.36 +/* NB. This must be shared amongst drivers if more things go in /dev/xeno */
    4.37 +static devfs_handle_t xeno_dev_dir;
    4.38 +
    4.39 +/* Only one process may open /dev/xeno/evtchn at any time. */
    4.40 +static unsigned long evtchn_dev_inuse;
    4.41 +
    4.42 +/* Notification ring, accessed via /dev/xeno/evtchn. */
    4.43 +static u16 *ring;
    4.44 +static unsigned int ring_cons, ring_prod;
    4.45 +
    4.46 +/* Processes wait on this queue via /dev/xeno/evtchn when ring is empty. */
    4.47 +static DECLARE_WAIT_QUEUE_HEAD(evtchn_wait);
    4.48 +static struct fasync_struct *evtchn_async_queue;
    4.49 +
    4.50 +static evtchn_receiver_t rx_fns[1024];
    4.51 +
    4.52 +static u32 pend_outstanding[32];
    4.53 +static u32 disc_outstanding[32];
    4.54 +
    4.55 +static spinlock_t lock;
    4.56 +
    4.57 +int evtchn_request_port(unsigned int port, evtchn_receiver_t rx_fn)
    4.58 +{
    4.59 +    unsigned long flags;
    4.60 +    int rc;
    4.61 +
    4.62 +    spin_lock_irqsave(&lock, flags);
    4.63 +
    4.64 +    if ( rx_fns[port] != NULL )
    4.65 +    {
    4.66 +        printk(KERN_ALERT "Event channel port %d already in use.\n", port);
    4.67 +        rc = -EINVAL;
    4.68 +    }
    4.69 +    else
    4.70 +    {
    4.71 +        rx_fns[port] = rx_fn;
    4.72 +        rc = 0;
    4.73 +    }
    4.74 +
    4.75 +    spin_unlock_irqrestore(&lock, flags);
    4.76 +
    4.77 +    return rc;
    4.78 +}
    4.79 +
    4.80 +int evtchn_free_port(unsigned int port)
    4.81 +{
    4.82 +    unsigned long flags;
    4.83 +    int rc;
    4.84 +
    4.85 +    spin_lock_irqsave(&lock, flags);
    4.86 +
    4.87 +    if ( rx_fns[port] == NULL )
    4.88 +    {
    4.89 +        printk(KERN_ALERT "Event channel port %d not in use.\n", port);
    4.90 +        rc = -EINVAL;
    4.91 +    }
    4.92 +    else
    4.93 +    {
    4.94 +        rx_fns[port] = NULL;
    4.95 +        rc = 0;
    4.96 +    }
    4.97 +
    4.98 +    spin_unlock_irqrestore(&lock, flags);
    4.99 +
   4.100 +    return rc;
   4.101 +}
   4.102 +
   4.103 +/*
   4.104 + * NB. Clearing port can race a notification from remote end. Caller must
   4.105 + * therefore recheck notification status on return to avoid missing events.
   4.106 + */
   4.107 +void evtchn_clear_port(unsigned int port)
   4.108 +{
   4.109 +    unsigned int p = port & PORTIDX_MASK;
   4.110 +    if ( unlikely(port & PORT_DISCONNECT) )
   4.111 +    {
   4.112 +        clear_bit(p, &HYPERVISOR_shared_info->event_channel_disc[0]);
   4.113 +        wmb(); /* clear the source first, then our quenchmask */
   4.114 +        clear_bit(p, &disc_outstanding[0]);
   4.115 +    }
   4.116 +    else
   4.117 +    {
   4.118 +        clear_bit(p, &HYPERVISOR_shared_info->event_channel_pend[0]);
   4.119 +        wmb(); /* clear the source first, then our quenchmask */
   4.120 +        clear_bit(p, &pend_outstanding[0]);
   4.121 +    }
   4.122 +}
   4.123 +
   4.124 +static inline void process_bitmask(u32 *sel, 
   4.125 +                                   u32 *mask,
   4.126 +                                   u32 *outstanding,
   4.127 +                                   unsigned int port_subtype)
   4.128 +{
   4.129 +    unsigned long l1, l2;
   4.130 +    unsigned int  l1_idx, l2_idx, port;
   4.131 +
   4.132 +    l1 = xchg(sel, 0);
   4.133 +    while ( (l1_idx = ffs(l1)) != 0 )
   4.134 +    {
   4.135 +        l1_idx--;
   4.136 +        l1 &= ~(1 << l1_idx);
   4.137 +
   4.138 +        l2 = mask[l1_idx] & ~outstanding[l1_idx];
   4.139 +        outstanding[l1_idx] |= l2;
   4.140 +        while ( (l2_idx = ffs(l2)) != 0 )
   4.141 +        {
   4.142 +            l2_idx--;
   4.143 +            l2 &= ~(1 << l2_idx);
   4.144 +
   4.145 +            port = (l1_idx * 32) + l2_idx;
   4.146 +            if ( rx_fns[port] != NULL )
   4.147 +            {
   4.148 +                (*rx_fns[port])(port | port_subtype);
   4.149 +            }
   4.150 +            else if ( ring != NULL )
   4.151 +            {
   4.152 +                ring[ring_prod] = (u16)(port | port_subtype);
   4.153 +                if ( ring_cons == ring_prod++ )
   4.154 +                {
   4.155 +                    wake_up_interruptible(&evtchn_wait);
   4.156 +                    kill_fasync(&evtchn_async_queue, SIGIO, POLL_IN);
   4.157 +                }
   4.158 +            }
   4.159 +        }
   4.160 +    }
   4.161 +
   4.162 +}
   4.163 +
   4.164 +static void evtchn_interrupt(int irq, void *dev_id, struct pt_regs *regs)
   4.165 +{
   4.166 +    shared_info_t *si = HYPERVISOR_shared_info;
   4.167 +    unsigned long flags;
   4.168 +
   4.169 +    spin_lock_irqsave(&lock, flags);
   4.170 +
   4.171 +    process_bitmask(&si->event_channel_pend_sel, 
   4.172 +                    &si->event_channel_pend[0],
   4.173 +                    &pend_outstanding[0],
   4.174 +                    PORT_NORMAL);
   4.175 +        
   4.176 +    process_bitmask(&si->event_channel_disc_sel,
   4.177 +                    &si->event_channel_disc[0],
   4.178 +                    &disc_outstanding[0],
   4.179 +                    PORT_DISCONNECT);
   4.180 +        
   4.181 +    spin_unlock_irqrestore(&lock, flags);
   4.182 +}
   4.183 +
   4.184 +static ssize_t evtchn_read(struct file *file, char *buf,
   4.185 +                           size_t count, loff_t *ppos)
   4.186 +{
   4.187 +    int rc;
   4.188 +    DECLARE_WAITQUEUE(wait, current);
   4.189 +
   4.190 +    add_wait_queue(&evtchn_wait, &wait);
   4.191 +
   4.192 +    for ( ; ; )
   4.193 +    {
   4.194 +        set_current_state(TASK_INTERRUPTIBLE);
   4.195 +
   4.196 +        if ( ring_cons != ring_prod )
   4.197 +            break;
   4.198 +
   4.199 +        if ( file->f_flags & O_NONBLOCK )
   4.200 +        {
   4.201 +            rc = -EAGAIN;
   4.202 +            goto out;
   4.203 +        }
   4.204 +
   4.205 +        if ( signal_pending(current) )
   4.206 +        {
   4.207 +            rc = -ERESTARTSYS;
   4.208 +            goto out;
   4.209 +        }
   4.210 +
   4.211 +        schedule();
   4.212 +    }
   4.213 +
   4.214 +    rc = -EINVAL;
   4.215 +    if ( count >= sizeof(ring_prod) )
   4.216 +        rc = put_user(ring_prod, (unsigned int *)buf);
   4.217 +    if ( rc == 0 )
   4.218 +        rc = sizeof(ring_prod);
   4.219 +
   4.220 + out:
   4.221 +    __set_current_state(TASK_RUNNING);
   4.222 +    remove_wait_queue(&evtchn_wait, &wait);
   4.223 +    return rc;
   4.224 +}
   4.225 +
   4.226 +static ssize_t evtchn_write(struct file *file, const char *buf,
   4.227 +                            size_t count, loff_t *ppos)
   4.228 +{
   4.229 +    int          rc = -EINVAL;
   4.230 +    unsigned int new_cons = 0;
   4.231 +
   4.232 +    if ( count >= sizeof(new_cons) )
   4.233 +        rc = get_user(new_cons, (unsigned int *)buf);
   4.234 +
   4.235 +    if ( rc != 0 )
   4.236 +        return rc;
   4.237 +
   4.238 +    rc = sizeof(new_cons);
   4.239 +
   4.240 +    while ( ring_cons != new_cons )
   4.241 +        evtchn_clear_port(ring[ring_cons++]);
   4.242 +
   4.243 +    return rc;
   4.244 +}
   4.245 +
   4.246 +static unsigned int evtchn_poll(struct file *file, poll_table *wait)
   4.247 +{
   4.248 +    unsigned int mask = POLLOUT | POLLWRNORM;
   4.249 +    poll_wait(file, &evtchn_wait, wait);
   4.250 +    if ( ring_cons != ring_prod )
   4.251 +        mask |= POLLIN | POLLRDNORM;
   4.252 +    return mask;
   4.253 +}
   4.254 +
   4.255 +static int evtchn_mmap(struct file *file, struct vm_area_struct *vma)
   4.256 +{
   4.257 +    /* Caller must map a single page of memory from 'file offset' zero. */
   4.258 +    if ( (vma->vm_pgoff != 0) || ((vma->vm_end - vma->vm_start) != PAGE_SIZE) )
   4.259 +        return -EINVAL;
   4.260 +
   4.261 +    /* Not a pageable area. */
   4.262 +    vma->vm_flags |= VM_RESERVED;
   4.263 +
   4.264 +    if ( remap_page_range(vma->vm_start, 0, PAGE_SIZE, vma->vm_page_prot) )
   4.265 +        return -EAGAIN;
   4.266 +
   4.267 +    return 0;
   4.268 +}
   4.269 +
   4.270 +static int evtchn_fasync(int fd, struct file *filp, int on)
   4.271 +{
   4.272 +    return fasync_helper(fd, filp, on, &evtchn_async_queue);
   4.273 +}
   4.274 +
   4.275 +static int evtchn_open(struct inode *inode, struct file *filp)
   4.276 +{
   4.277 +    u16         *_ring;
   4.278 +    u32          m;
   4.279 +    unsigned int i, j;
   4.280 +
   4.281 +    if ( test_and_set_bit(0, &evtchn_dev_inuse) )
   4.282 +        return -EBUSY;
   4.283 +
   4.284 +    /* Allocate outside locked region so that we can use GFP_KERNEL. */
   4.285 +    if ( (_ring = (u16 *)get_free_page(GFP_KERNEL)) == NULL )
   4.286 +        return -ENOMEM;
   4.287 +
   4.288 +    spin_lock_irq(&lock);
   4.289 +
   4.290 +    ring = _ring;
   4.291 +
   4.292 +    /* Initialise the ring with currently outstanding notifications. */
   4.293 +    ring_cons = ring_prod = 0;
   4.294 +    for ( i = 0; i < 32; i++ )
   4.295 +    {
   4.296 +        m = pend_outstanding[i];
   4.297 +        while ( (j = ffs(m)) != 0 )
   4.298 +        {
   4.299 +            m &= ~(1 << --j);
   4.300 +            if ( rx_fns[(i * 32) + j] == NULL )
   4.301 +                ring[ring_prod++] = (u16)(((i * 32) + j) | PORT_NORMAL);
   4.302 +        }
   4.303 +
   4.304 +        m = disc_outstanding[i];
   4.305 +        while ( (j = ffs(m)) != 0 )
   4.306 +        {
   4.307 +            m &= ~(1 << --j);
   4.308 +            if ( rx_fns[(i * 32) + j] == NULL )
   4.309 +                ring[ring_prod++] = (u16)(((i * 32) + j) | PORT_DISCONNECT);
   4.310 +        }
   4.311 +    }
   4.312 +
   4.313 +    spin_unlock_irq(&lock);
   4.314 +
   4.315 +    MOD_INC_USE_COUNT;
   4.316 +
   4.317 +    return 0;
   4.318 +}
   4.319 +
   4.320 +static int evtchn_release(struct inode *inode, struct file *filp)
   4.321 +{
   4.322 +    spin_lock_irq(&lock);
   4.323 +    if ( ring != NULL )
   4.324 +    {
   4.325 +        free_page((unsigned long)ring);
   4.326 +        ring = NULL;
   4.327 +    }
   4.328 +    spin_unlock_irq(&lock);
   4.329 +
   4.330 +    evtchn_dev_inuse = 0;
   4.331 +
   4.332 +    MOD_DEC_USE_COUNT;
   4.333 +
   4.334 +    return 0;
   4.335 +}
   4.336 +
   4.337 +static struct file_operations evtchn_fops = {
   4.338 +    owner:    THIS_MODULE,
   4.339 +    read:     evtchn_read,
   4.340 +    write:    evtchn_write,
   4.341 +    poll:     evtchn_poll,
   4.342 +    mmap:     evtchn_mmap,
   4.343 +    fasync:   evtchn_fasync,
   4.344 +    open:     evtchn_open,
   4.345 +    release:  evtchn_release
   4.346 +};
   4.347 +
   4.348 +static struct miscdevice evtchn_miscdev = {
   4.349 +    minor:    EVTCHN_MINOR,
   4.350 +    name:     "evtchn",
   4.351 +    fops:     &evtchn_fops
   4.352 +};
   4.353 +
   4.354 +static int __init init_module(void)
   4.355 +{
   4.356 +    devfs_handle_t symlink_handle;
   4.357 +    int            err, pos;
   4.358 +    char           link_dest[64];
   4.359 +
   4.360 +    /* (DEVFS) create '/dev/misc/evtchn'. */
   4.361 +    err = misc_register(&evtchn_miscdev);
   4.362 +    if ( err != 0 )
   4.363 +    {
   4.364 +        printk(KERN_ALERT "Could not register /dev/misc/evtchn\n");
   4.365 +        return err;
   4.366 +    }
   4.367 +
   4.368 +    /* (DEVFS) create directory '/dev/xeno'. */
   4.369 +    xeno_dev_dir = devfs_mk_dir(NULL, "xeno", NULL);
   4.370 +
   4.371 +    /* (DEVFS) &link_dest[pos] == '../misc/evtchn'. */
   4.372 +    pos = devfs_generate_path(evtchn_miscdev.devfs_handle, 
   4.373 +                              &link_dest[3], 
   4.374 +                              sizeof(link_dest) - 3);
   4.375 +    if ( pos >= 0 )
   4.376 +        strncpy(&link_dest[pos], "../", 3);
   4.377 +
   4.378 +    /* (DEVFS) symlink '/dev/xeno/evtchn' -> '../misc/evtchn'. */
   4.379 +    (void)devfs_mk_symlink(xeno_dev_dir, 
   4.380 +                           "evtchn", 
   4.381 +                           DEVFS_FL_DEFAULT, 
   4.382 +                           &link_dest[pos],
   4.383 +                           &symlink_handle, 
   4.384 +                           NULL);
   4.385 +
   4.386 +    /* (DEVFS) automatically destroy the symlink with its destination. */
   4.387 +    devfs_auto_unregister(evtchn_miscdev.devfs_handle, symlink_handle);
   4.388 +
   4.389 +    err = request_irq(_EVENT_EVTCHN, evtchn_interrupt, 0, "evtchn", NULL);
   4.390 +    if ( err != 0 )
   4.391 +    {
   4.392 +        printk(KERN_ALERT "Could not allocate evtchn receive interrupt\n");
   4.393 +        return err;
   4.394 +    }
   4.395 +
   4.396 +    return 0;
   4.397 +}
   4.398 +
   4.399 +static void cleanup_module(void)
   4.400 +{
   4.401 +    free_irq(_EVENT_EVTCHN, NULL);
   4.402 +    misc_deregister(&evtchn_miscdev);
   4.403 +}
   4.404 +
   4.405 +module_init(init_module);
   4.406 +module_exit(cleanup_module);
     5.1 --- a/xenolinux-2.4.25-sparse/arch/xeno/drivers/network/network.c	Fri Feb 27 15:19:27 2004 +0000
     5.2 +++ b/xenolinux-2.4.25-sparse/arch/xeno/drivers/network/network.c	Sun Feb 29 15:51:23 2004 +0000
     5.3 @@ -529,7 +529,7 @@ static struct notifier_block notifier_in
     5.4  };
     5.5  
     5.6  
     5.7 -int __init init_module(void)
     5.8 +static int __init init_module(void)
     5.9  {
    5.10      int i, fixmap_idx=-1, err;
    5.11      struct net_device *dev;
     6.1 --- a/xenolinux-2.4.25-sparse/arch/xeno/kernel/hypervisor.c	Fri Feb 27 15:19:27 2004 +0000
     6.2 +++ b/xenolinux-2.4.25-sparse/arch/xeno/kernel/hypervisor.c	Sun Feb 29 15:51:23 2004 +0000
     6.3 @@ -18,8 +18,6 @@ int nr_multicall_ents = 0;
     6.4  
     6.5  static unsigned long event_mask = 0;
     6.6  
     6.7 -void frobb(void) {}
     6.8 -
     6.9  void do_hypervisor_callback(struct pt_regs *regs)
    6.10  {
    6.11      unsigned long events, flags;