aboutsummaryrefslogtreecommitdiffstats
path: root/xenolinux-2.4.25-sparse/arch
diff options
context:
space:
mode:
authorkaf24@scramble.cl.cam.ac.uk <kaf24@scramble.cl.cam.ac.uk>2004-02-29 15:51:23 +0000
committerkaf24@scramble.cl.cam.ac.uk <kaf24@scramble.cl.cam.ac.uk>2004-02-29 15:51:23 +0000
commit5fe26fde8cc56c4520cd72644d5af9b51553baf4 (patch)
tree49d5ab9cd62470893c5eac5c4b426c9c1bcd0764 /xenolinux-2.4.25-sparse/arch
parent852c5cea72e07706be1e778f6cdd03c8026ee966 (diff)
downloadxen-5fe26fde8cc56c4520cd72644d5af9b51553baf4.tar.gz
xen-5fe26fde8cc56c4520cd72644d5af9b51553baf4.tar.bz2
xen-5fe26fde8cc56c4520cd72644d5af9b51553baf4.zip
bitkeeper revision 1.756 (40420a7bDsT_OI1_rz4fkewUJosvRA)
xl_evtchn.c, Makefile: new file hypervisor.c, network.c, Makefile: Event-channel demuxing in Xenolinux.
Diffstat (limited to 'xenolinux-2.4.25-sparse/arch')
-rw-r--r--xenolinux-2.4.25-sparse/arch/xeno/Makefile4
-rw-r--r--xenolinux-2.4.25-sparse/arch/xeno/drivers/evtchn/Makefile3
-rw-r--r--xenolinux-2.4.25-sparse/arch/xeno/drivers/evtchn/xl_evtchn.c403
-rw-r--r--xenolinux-2.4.25-sparse/arch/xeno/drivers/network/network.c2
-rw-r--r--xenolinux-2.4.25-sparse/arch/xeno/kernel/hypervisor.c2
5 files changed, 410 insertions, 4 deletions
diff --git a/xenolinux-2.4.25-sparse/arch/xeno/Makefile b/xenolinux-2.4.25-sparse/arch/xeno/Makefile
index 815c28107b..710caaddbe 100644
--- a/xenolinux-2.4.25-sparse/arch/xeno/Makefile
+++ b/xenolinux-2.4.25-sparse/arch/xeno/Makefile
@@ -48,7 +48,8 @@ HEAD := arch/xeno/kernel/head.o arch/xeno/kernel/init_task.o
SUBDIRS += arch/xeno/kernel arch/xeno/mm arch/xeno/lib
SUBDIRS += arch/xeno/drivers/console arch/xeno/drivers/network
-SUBDIRS += arch/xeno/drivers/block arch/xeno/drivers/balloon
+SUBDIRS += arch/xeno/drivers/evtchn arch/xeno/drivers/block
+SUBDIRS += arch/xeno/drivers/balloon
ifdef CONFIG_XENO_PRIV
SUBDIRS += arch/xeno/drivers/dom0
endif
@@ -56,6 +57,7 @@ endif
CORE_FILES += arch/xeno/kernel/kernel.o arch/xeno/mm/mm.o
CORE_FILES += arch/xeno/drivers/console/con.o
CORE_FILES += arch/xeno/drivers/block/blk.o
+CORE_FILES += arch/xeno/drivers/evtchn/evtchn.o
CORE_FILES += arch/xeno/drivers/network/net.o
ifdef CONFIG_XENO_PRIV
CORE_FILES += arch/xeno/drivers/dom0/dom0.o
diff --git a/xenolinux-2.4.25-sparse/arch/xeno/drivers/evtchn/Makefile b/xenolinux-2.4.25-sparse/arch/xeno/drivers/evtchn/Makefile
new file mode 100644
index 0000000000..8384c8658b
--- /dev/null
+++ b/xenolinux-2.4.25-sparse/arch/xeno/drivers/evtchn/Makefile
@@ -0,0 +1,3 @@
+O_TARGET := evtchn.o
+obj-y := xl_evtchn.o
+include $(TOPDIR)/Rules.make
diff --git a/xenolinux-2.4.25-sparse/arch/xeno/drivers/evtchn/xl_evtchn.c b/xenolinux-2.4.25-sparse/arch/xeno/drivers/evtchn/xl_evtchn.c
new file mode 100644
index 0000000000..82af52ec8c
--- /dev/null
+++ b/xenolinux-2.4.25-sparse/arch/xeno/drivers/evtchn/xl_evtchn.c
@@ -0,0 +1,403 @@
+/******************************************************************************
+ * xl_evtchn.c
+ *
+ * Xenolinux driver for receiving and demuxing event-channel signals.
+ *
+ * Copyright (c) 2004, K A Fraser
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/errno.h>
+#include <linux/miscdevice.h>
+#include <linux/major.h>
+#include <linux/proc_fs.h>
+#include <linux/devfs_fs_kernel.h>
+#include <linux/stat.h>
+#include <linux/poll.h>
+
+typedef void (*evtchn_receiver_t)(unsigned int);
+#define PORT_NORMAL 0x0000
+#define PORT_DISCONNECT 0x8000
+#define PORTIDX_MASK 0x7fff
+
+/* /dev/xeno/evtchn resides at device number major=10, minor=200 */
+#define EVTCHN_MINOR 200
+
+/* NB. This must be shared amongst drivers if more things go in /dev/xeno */
+static devfs_handle_t xeno_dev_dir;
+
+/* Only one process may open /dev/xeno/evtchn at any time. */
+static unsigned long evtchn_dev_inuse;
+
+/* Notification ring, accessed via /dev/xeno/evtchn. */
+static u16 *ring;
+static unsigned int ring_cons, ring_prod;
+
+/* Processes wait on this queue via /dev/xeno/evtchn when ring is empty. */
+static DECLARE_WAIT_QUEUE_HEAD(evtchn_wait);
+static struct fasync_struct *evtchn_async_queue;
+
+static evtchn_receiver_t rx_fns[1024];
+
+static u32 pend_outstanding[32];
+static u32 disc_outstanding[32];
+
+static spinlock_t lock;
+
+int evtchn_request_port(unsigned int port, evtchn_receiver_t rx_fn)
+{
+ unsigned long flags;
+ int rc;
+
+ spin_lock_irqsave(&lock, flags);
+
+ if ( rx_fns[port] != NULL )
+ {
+ printk(KERN_ALERT "Event channel port %d already in use.\n", port);
+ rc = -EINVAL;
+ }
+ else
+ {
+ rx_fns[port] = rx_fn;
+ rc = 0;
+ }
+
+ spin_unlock_irqrestore(&lock, flags);
+
+ return rc;
+}
+
+int evtchn_free_port(unsigned int port)
+{
+ unsigned long flags;
+ int rc;
+
+ spin_lock_irqsave(&lock, flags);
+
+ if ( rx_fns[port] == NULL )
+ {
+ printk(KERN_ALERT "Event channel port %d not in use.\n", port);
+ rc = -EINVAL;
+ }
+ else
+ {
+ rx_fns[port] = NULL;
+ rc = 0;
+ }
+
+ spin_unlock_irqrestore(&lock, flags);
+
+ return rc;
+}
+
+/*
+ * NB. Clearing port can race a notification from remote end. Caller must
+ * therefore recheck notification status on return to avoid missing events.
+ */
+void evtchn_clear_port(unsigned int port)
+{
+ unsigned int p = port & PORTIDX_MASK;
+ if ( unlikely(port & PORT_DISCONNECT) )
+ {
+ clear_bit(p, &HYPERVISOR_shared_info->event_channel_disc[0]);
+ wmb(); /* clear the source first, then our quenchmask */
+ clear_bit(p, &disc_outstanding[0]);
+ }
+ else
+ {
+ clear_bit(p, &HYPERVISOR_shared_info->event_channel_pend[0]);
+ wmb(); /* clear the source first, then our quenchmask */
+ clear_bit(p, &pend_outstanding[0]);
+ }
+}
+
+static inline void process_bitmask(u32 *sel,
+ u32 *mask,
+ u32 *outstanding,
+ unsigned int port_subtype)
+{
+ unsigned long l1, l2;
+ unsigned int l1_idx, l2_idx, port;
+
+ l1 = xchg(sel, 0);
+ while ( (l1_idx = ffs(l1)) != 0 )
+ {
+ l1_idx--;
+ l1 &= ~(1 << l1_idx);
+
+ l2 = mask[l1_idx] & ~outstanding[l1_idx];
+ outstanding[l1_idx] |= l2;
+ while ( (l2_idx = ffs(l2)) != 0 )
+ {
+ l2_idx--;
+ l2 &= ~(1 << l2_idx);
+
+ port = (l1_idx * 32) + l2_idx;
+ if ( rx_fns[port] != NULL )
+ {
+ (*rx_fns[port])(port | port_subtype);
+ }
+ else if ( ring != NULL )
+ {
+ ring[ring_prod] = (u16)(port | port_subtype);
+ if ( ring_cons == ring_prod++ )
+ {
+ wake_up_interruptible(&evtchn_wait);
+ kill_fasync(&evtchn_async_queue, SIGIO, POLL_IN);
+ }
+ }
+ }
+ }
+
+}
+
+static void evtchn_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+ shared_info_t *si = HYPERVISOR_shared_info;
+ unsigned long flags;
+
+ spin_lock_irqsave(&lock, flags);
+
+ process_bitmask(&si->event_channel_pend_sel,
+ &si->event_channel_pend[0],
+ &pend_outstanding[0],
+ PORT_NORMAL);
+
+ process_bitmask(&si->event_channel_disc_sel,
+ &si->event_channel_disc[0],
+ &disc_outstanding[0],
+ PORT_DISCONNECT);
+
+ spin_unlock_irqrestore(&lock, flags);
+}
+
+static ssize_t evtchn_read(struct file *file, char *buf,
+ size_t count, loff_t *ppos)
+{
+ int rc;
+ DECLARE_WAITQUEUE(wait, current);
+
+ add_wait_queue(&evtchn_wait, &wait);
+
+ for ( ; ; )
+ {
+ set_current_state(TASK_INTERRUPTIBLE);
+
+ if ( ring_cons != ring_prod )
+ break;
+
+ if ( file->f_flags & O_NONBLOCK )
+ {
+ rc = -EAGAIN;
+ goto out;
+ }
+
+ if ( signal_pending(current) )
+ {
+ rc = -ERESTARTSYS;
+ goto out;
+ }
+
+ schedule();
+ }
+
+ rc = -EINVAL;
+ if ( count >= sizeof(ring_prod) )
+ rc = put_user(ring_prod, (unsigned int *)buf);
+ if ( rc == 0 )
+ rc = sizeof(ring_prod);
+
+ out:
+ __set_current_state(TASK_RUNNING);
+ remove_wait_queue(&evtchn_wait, &wait);
+ return rc;
+}
+
+static ssize_t evtchn_write(struct file *file, const char *buf,
+ size_t count, loff_t *ppos)
+{
+ int rc = -EINVAL;
+ unsigned int new_cons = 0;
+
+ if ( count >= sizeof(new_cons) )
+ rc = get_user(new_cons, (unsigned int *)buf);
+
+ if ( rc != 0 )
+ return rc;
+
+ rc = sizeof(new_cons);
+
+ while ( ring_cons != new_cons )
+ evtchn_clear_port(ring[ring_cons++]);
+
+ return rc;
+}
+
+static unsigned int evtchn_poll(struct file *file, poll_table *wait)
+{
+ unsigned int mask = POLLOUT | POLLWRNORM;
+ poll_wait(file, &evtchn_wait, wait);
+ if ( ring_cons != ring_prod )
+ mask |= POLLIN | POLLRDNORM;
+ return mask;
+}
+
+static int evtchn_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ /* Caller must map a single page of memory from 'file offset' zero. */
+ if ( (vma->vm_pgoff != 0) || ((vma->vm_end - vma->vm_start) != PAGE_SIZE) )
+ return -EINVAL;
+
+ /* Not a pageable area. */
+ vma->vm_flags |= VM_RESERVED;
+
+ if ( remap_page_range(vma->vm_start, 0, PAGE_SIZE, vma->vm_page_prot) )
+ return -EAGAIN;
+
+ return 0;
+}
+
+static int evtchn_fasync(int fd, struct file *filp, int on)
+{
+ return fasync_helper(fd, filp, on, &evtchn_async_queue);
+}
+
+static int evtchn_open(struct inode *inode, struct file *filp)
+{
+ u16 *_ring;
+ u32 m;
+ unsigned int i, j;
+
+ if ( test_and_set_bit(0, &evtchn_dev_inuse) )
+ return -EBUSY;
+
+ /* Allocate outside locked region so that we can use GFP_KERNEL. */
+ if ( (_ring = (u16 *)get_free_page(GFP_KERNEL)) == NULL )
+ return -ENOMEM;
+
+ spin_lock_irq(&lock);
+
+ ring = _ring;
+
+ /* Initialise the ring with currently outstanding notifications. */
+ ring_cons = ring_prod = 0;
+ for ( i = 0; i < 32; i++ )
+ {
+ m = pend_outstanding[i];
+ while ( (j = ffs(m)) != 0 )
+ {
+ m &= ~(1 << --j);
+ if ( rx_fns[(i * 32) + j] == NULL )
+ ring[ring_prod++] = (u16)(((i * 32) + j) | PORT_NORMAL);
+ }
+
+ m = disc_outstanding[i];
+ while ( (j = ffs(m)) != 0 )
+ {
+ m &= ~(1 << --j);
+ if ( rx_fns[(i * 32) + j] == NULL )
+ ring[ring_prod++] = (u16)(((i * 32) + j) | PORT_DISCONNECT);
+ }
+ }
+
+ spin_unlock_irq(&lock);
+
+ MOD_INC_USE_COUNT;
+
+ return 0;
+}
+
+static int evtchn_release(struct inode *inode, struct file *filp)
+{
+ spin_lock_irq(&lock);
+ if ( ring != NULL )
+ {
+ free_page((unsigned long)ring);
+ ring = NULL;
+ }
+ spin_unlock_irq(&lock);
+
+ evtchn_dev_inuse = 0;
+
+ MOD_DEC_USE_COUNT;
+
+ return 0;
+}
+
+static struct file_operations evtchn_fops = {
+ owner: THIS_MODULE,
+ read: evtchn_read,
+ write: evtchn_write,
+ poll: evtchn_poll,
+ mmap: evtchn_mmap,
+ fasync: evtchn_fasync,
+ open: evtchn_open,
+ release: evtchn_release
+};
+
+static struct miscdevice evtchn_miscdev = {
+ minor: EVTCHN_MINOR,
+ name: "evtchn",
+ fops: &evtchn_fops
+};
+
+static int __init init_module(void)
+{
+ devfs_handle_t symlink_handle;
+ int err, pos;
+ char link_dest[64];
+
+ /* (DEVFS) create '/dev/misc/evtchn'. */
+ err = misc_register(&evtchn_miscdev);
+ if ( err != 0 )
+ {
+ printk(KERN_ALERT "Could not register /dev/misc/evtchn\n");
+ return err;
+ }
+
+ /* (DEVFS) create directory '/dev/xeno'. */
+ xeno_dev_dir = devfs_mk_dir(NULL, "xeno", NULL);
+
+ /* (DEVFS) &link_dest[pos] == '../misc/evtchn'. */
+ pos = devfs_generate_path(evtchn_miscdev.devfs_handle,
+ &link_dest[3],
+ sizeof(link_dest) - 3);
+ if ( pos >= 0 )
+ strncpy(&link_dest[pos], "../", 3);
+
+ /* (DEVFS) symlink '/dev/xeno/evtchn' -> '../misc/evtchn'. */
+ (void)devfs_mk_symlink(xeno_dev_dir,
+ "evtchn",
+ DEVFS_FL_DEFAULT,
+ &link_dest[pos],
+ &symlink_handle,
+ NULL);
+
+ /* (DEVFS) automatically destroy the symlink with its destination. */
+ devfs_auto_unregister(evtchn_miscdev.devfs_handle, symlink_handle);
+
+ err = request_irq(_EVENT_EVTCHN, evtchn_interrupt, 0, "evtchn", NULL);
+ if ( err != 0 )
+ {
+ printk(KERN_ALERT "Could not allocate evtchn receive interrupt\n");
+ return err;
+ }
+
+ return 0;
+}
+
+static void cleanup_module(void)
+{
+ free_irq(_EVENT_EVTCHN, NULL);
+ misc_deregister(&evtchn_miscdev);
+}
+
+module_init(init_module);
+module_exit(cleanup_module);
diff --git a/xenolinux-2.4.25-sparse/arch/xeno/drivers/network/network.c b/xenolinux-2.4.25-sparse/arch/xeno/drivers/network/network.c
index 29f7c2224f..95b4c45501 100644
--- a/xenolinux-2.4.25-sparse/arch/xeno/drivers/network/network.c
+++ b/xenolinux-2.4.25-sparse/arch/xeno/drivers/network/network.c
@@ -529,7 +529,7 @@ static struct notifier_block notifier_inetdev = {
};
-int __init init_module(void)
+static int __init init_module(void)
{
int i, fixmap_idx=-1, err;
struct net_device *dev;
diff --git a/xenolinux-2.4.25-sparse/arch/xeno/kernel/hypervisor.c b/xenolinux-2.4.25-sparse/arch/xeno/kernel/hypervisor.c
index 3f414e9876..8e7e144137 100644
--- a/xenolinux-2.4.25-sparse/arch/xeno/kernel/hypervisor.c
+++ b/xenolinux-2.4.25-sparse/arch/xeno/kernel/hypervisor.c
@@ -18,8 +18,6 @@ int nr_multicall_ents = 0;
static unsigned long event_mask = 0;
-void frobb(void) {}
-
void do_hypervisor_callback(struct pt_regs *regs)
{
unsigned long events, flags;