ia64/xen-unstable

changeset 1249:4ca11b869b2f

bitkeeper revision 1.825.3.10 (4065558aPBWky8sW_ub8imsOf_yTwg)

Many files:
Cleaned up user-space event-channel handling (now better reflects the underlying abstraction). Also simplified handling of exceptional notifications (now a special case of a normal notification).
author kaf24@scramble.cl.cam.ac.uk
date Sat Mar 27 10:20:58 2004 +0000 (2004-03-27)
parents dbb603dba154
children b2c2c29b1e99
files tools/xend/lib/main.py tools/xend/lib/manager.py tools/xend/lib/utils.c xen/common/event_channel.c xen/include/hypervisor-ifs/hypervisor-if.h xen/include/xen/event.h xenolinux-2.4.25-sparse/arch/xen/drivers/console/console.c xenolinux-2.4.25-sparse/arch/xen/drivers/evtchn/evtchn.c xenolinux-2.4.25-sparse/arch/xen/kernel/evtchn.c xenolinux-2.4.25-sparse/include/asm-xen/evtchn.h
line diff
     1.1 --- a/tools/xend/lib/main.py	Fri Mar 26 19:57:09 2004 +0000
     1.2 +++ b/tools/xend/lib/main.py	Sat Mar 27 10:20:58 2004 +0000
     1.3 @@ -41,8 +41,7 @@ def daemon_loop():
     1.4  
     1.5      # Interface via which we receive event notifications from other guest
     1.6      # OSes. This interface also allows us to clear/acknowledge outstanding
     1.7 -    # notifications --- successive notifications for the same channel are
     1.8 -    # dropped until the first notification is cleared.
     1.9 +    # notifications.
    1.10      notifier = xend.utils.notifier()
    1.11  
    1.12      ##
    1.13 @@ -169,56 +168,48 @@ def daemon_loop():
    1.14                  break
    1.15              (idx, type) = notification
    1.16  
    1.17 +            if not control_list.has_key(idx):
    1.18 +                continue
    1.19 +
    1.20 +            (port, rbuf, wbuf, con_if) = control_list[idx]
    1.21 +            work_done = False
    1.22 +
    1.23              # If we pick up a disconnect notification then we do any necessary
    1.24 -            # cleanup, even if the event channel doesn't belong to us.
    1.25 -            # This is intended to prevent the event-channel port space from
    1.26 -            # getting clogged with stale connections.
    1.27 -            if type == notifier.DISCONNECT:
    1.28 +            # cleanup.
    1.29 +            if type == notifier.EXCEPTION:
    1.30                  ret = xc.evtchn_status(idx)
    1.31 -                if ret['status'] == 'interdomain':
    1.32 -                    notifier.clear(idx, notifier.NORMAL)
    1.33 -                    notifier.clear(idx, notifier.DISCONNECT)
    1.34 -                    if control_list.has_key(idx):
    1.35 -                        (port, rbuf, wbuf, con_if) =  control_list[idx]
    1.36 -                        con_if.close()
    1.37 -                        del control_list[idx], port, rbuf, wbuf, con_if
    1.38 -                elif ret['status'] == 'unbound':
    1.39 -                    # There's noone to do the closure for us...
    1.40 -                    xc.evtchn_close(idx)
    1.41 -
    1.42 -            # A standard notification: probably means there are messages to
    1.43 -            # read or that there is space to write messages.
    1.44 -            elif type == notifier.NORMAL and control_list.has_key(idx):
    1.45 -                (port, rbuf, wbuf, con_if) = control_list[idx]
    1.46 -                work_done = False
    1.47 +                if ret['status'] == 'unbound':
    1.48 +                    notifier.unbind(idx)
    1.49 +                    con_if.close()
    1.50 +                    del control_list[idx], port, rbuf, wbuf, con_if
    1.51 +                    continue
    1.52  
    1.53 -                # We clear the notification before doing any work, to avoid
    1.54 -                # races.
    1.55 -                notifier.clear(idx, notifier.NORMAL)
    1.56 +            # Read incoming requests. Currently assume that request
    1.57 +            # message always containb console data.
    1.58 +            while port.request_to_read():
    1.59 +                msg = port.read_request()
    1.60 +                rbuf.write(msg.get_payload())
    1.61 +                port.write_response(msg)
    1.62 +                work_done = True
    1.63  
    1.64 -                # Read incoming requests. Currently assume that request
    1.65 -                # message always containb console data.
    1.66 -                while port.request_to_read():
    1.67 -                    msg = port.read_request()
    1.68 -                    rbuf.write(msg.get_payload())
    1.69 -                    port.write_response(msg)
    1.70 -                    work_done = True
    1.71 +            # Incoming responses are currently thrown on the floor.
    1.72 +            while port.response_to_read():
    1.73 +                msg = port.read_response()
    1.74 +                work_done = True
    1.75  
    1.76 -                # Incoming responses are currently thrown on the floor.
    1.77 -                while port.response_to_read():
    1.78 -                    msg = port.read_response()
    1.79 -                    work_done = True
    1.80 +            # Send as much pending console data as there is room for.
    1.81 +            while not wbuf.empty() and port.space_to_write_request():
    1.82 +                msg = xend.utils.message(0, 0, 0)
    1.83 +                msg.append_payload(wbuf.read(msg.MAX_PAYLOAD))
    1.84 +                port.write_request(msg)
    1.85 +                work_done = True
    1.86  
    1.87 -                # Send as much pending console data as there is room for.
    1.88 -                while not wbuf.empty() and port.space_to_write_request():
    1.89 -                    msg = xend.utils.message(0, 0, 0)
    1.90 -                    msg.append_payload(wbuf.read(msg.MAX_PAYLOAD))
    1.91 -                    port.write_request(msg)
    1.92 -                    work_done = True
    1.93 +            # Finally, notify the remote end of any work that we did.
    1.94 +            if work_done:
    1.95 +                port.notify()
    1.96  
    1.97 -                # Finally, notify the remote end of any work that we did.
    1.98 -                if work_done:
    1.99 -                    port.notify()
   1.100 +            # Unmask notifications for this port.
   1.101 +            notifier.unmask(idx)
   1.102  
   1.103  
   1.104  
     2.1 --- a/tools/xend/lib/manager.py	Fri Mar 26 19:57:09 2004 +0000
     2.2 +++ b/tools/xend/lib/manager.py	Sat Mar 27 10:20:58 2004 +0000
     2.3 @@ -14,10 +14,9 @@ import xend.console, xend.main, xend.uti
     2.4  ##  automatically allocated.
     2.5  ##
     2.6  def new_control_interface(dom, console_port=-1):
     2.7 -    # Allocate an event channel. Clear pending notifications.
     2.8 +    # Allocate an event channel and binbd to it.
     2.9      port = xend.utils.port(dom)
    2.10 -    xend.main.notifier.clear(port.local_port, xend.main.notifier.NORMAL)
    2.11 -    xend.main.notifier.clear(port.local_port, xend.main.notifier.DISCONNECT)
    2.12 +    xend.main.notifier.bind(port.local_port)
    2.13      
    2.14      # If necessary, compute a suitable TCP port for console I/O.
    2.15      if console_port < 0:
     3.1 --- a/tools/xend/lib/utils.c	Fri Mar 26 19:57:09 2004 +0000
     3.2 +++ b/tools/xend/lib/utils.c	Sat Mar 27 10:20:58 2004 +0000
     3.3 @@ -33,9 +33,15 @@
     3.4  #define EVTCHN_DEV_MAJOR 10
     3.5  #define EVTCHN_DEV_MINOR 200
     3.6  #define PORT_NORMAL     0x0000   /* A standard event notification.      */ 
     3.7 -#define PORT_DISCONNECT 0x8000   /* A port-disconnect notification.     */
     3.8 +#define PORT_EXCEPTION  0x8000   /* An exceptional notification.        */
     3.9  #define PORTIDX_MASK    0x7fff   /* Strip subtype to obtain port index. */
    3.10 -#define EVTCHN_RESET _IO('E', 1) /* Clear notification buffer. Clear errors. */
    3.11 +/* /dev/xen/evtchn ioctls: */
    3.12 +/* EVTCHN_RESET: Clear and reinit the event buffer. Clear error condition. */
    3.13 +#define EVTCHN_RESET  _IO('E', 1)
    3.14 +/* EVTCHN_BIND: Bind to teh specified event-channel port. */
    3.15 +#define EVTCHN_BIND   _IO('E', 2)
    3.16 +/* EVTCHN_UNBIND: Unbind from the specified event-channel port. */
    3.17 +#define EVTCHN_UNBIND _IO('E', 3)
    3.18  
    3.19  /* Size of a machine page frame. */
    3.20  #define PAGE_SIZE 4096
    3.21 @@ -76,18 +82,48 @@ static PyObject *xu_notifier_read(PyObje
    3.22      return Py_None;
    3.23  }
    3.24  
    3.25 -static PyObject *xu_notifier_clear(PyObject *self, PyObject *args)
    3.26 +static PyObject *xu_notifier_unmask(PyObject *self, PyObject *args)
    3.27  {
    3.28      xu_notifier_object *xun = (xu_notifier_object *)self;
    3.29      u16 v;
    3.30 -    int idx, type;
    3.31 +    int idx;
    3.32  
    3.33 -    if ( !PyArg_ParseTuple(args, "ii", &idx, &type) )
    3.34 +    if ( !PyArg_ParseTuple(args, "i", &idx) )
    3.35          return NULL;
    3.36 +
    3.37 +    v = (u16)idx;
    3.38      
    3.39 -    v = (u16)idx | (u16)type;
    3.40 +    (void)write(xun->evtchn_fd, &v, sizeof(v));
    3.41 +
    3.42 +    Py_INCREF(Py_None);
    3.43 +    return Py_None;
    3.44 +}
    3.45 +
    3.46 +static PyObject *xu_notifier_bind(PyObject *self, PyObject *args)
    3.47 +{
    3.48 +    xu_notifier_object *xun = (xu_notifier_object *)self;
    3.49 +    int idx;
    3.50 +
    3.51 +    if ( !PyArg_ParseTuple(args, "i", &idx) )
    3.52 +        return NULL;
    3.53  
    3.54 -    (void)write(xun->evtchn_fd, &v, sizeof(v));
    3.55 +    if ( ioctl(xun->evtchn_fd, EVTCHN_BIND, idx) != 0 )
    3.56 +        return PyErr_SetFromErrno(PyExc_IOError);
    3.57 +
    3.58 +    Py_INCREF(Py_None);
    3.59 +    return Py_None;
    3.60 +}
    3.61 +
    3.62 +static PyObject *xu_notifier_unbind(PyObject *self, PyObject *args)
    3.63 +{
    3.64 +    xu_notifier_object *xun = (xu_notifier_object *)self;
    3.65 +    int idx;
    3.66 +
    3.67 +    if ( !PyArg_ParseTuple(args, "i", &idx) )
    3.68 +        return NULL;
    3.69 +
    3.70 +    if ( ioctl(xun->evtchn_fd, EVTCHN_UNBIND, idx) != 0 )
    3.71 +        return PyErr_SetFromErrno(PyExc_IOError);
    3.72  
    3.73      Py_INCREF(Py_None);
    3.74      return Py_None;
    3.75 @@ -105,10 +141,20 @@ static PyMethodDef xu_notifier_methods[]
    3.76        METH_VARARGS,
    3.77        "Read a (@port, @type) pair.\n" },
    3.78  
    3.79 -    { "clear", 
    3.80 -      (PyCFunction)xu_notifier_clear,
    3.81 +    { "unmask", 
    3.82 +      (PyCFunction)xu_notifier_unmask,
    3.83        METH_VARARGS,
    3.84 -      "Clear a (@port, @type) pair.\n" },
    3.85 +      "Unmask notifications for a @port.\n" },
    3.86 +
    3.87 +    { "bind", 
    3.88 +      (PyCFunction)xu_notifier_bind,
    3.89 +      METH_VARARGS,
    3.90 +      "Get notifications for a @port.\n" },
    3.91 +
    3.92 +    { "unbind", 
    3.93 +      (PyCFunction)xu_notifier_unbind,
    3.94 +      METH_VARARGS,
    3.95 +      "No longer get notifications for a @port.\n" },
    3.96  
    3.97      { "fileno", 
    3.98        (PyCFunction)xu_notifier_fileno,
    3.99 @@ -147,8 +193,8 @@ static PyObject *xu_notifier_new(PyObjec
   3.100  
   3.101  static PyObject *xu_notifier_getattr(PyObject *obj, char *name)
   3.102  {
   3.103 -    if ( strcmp(name, "DISCONNECT") == 0 )
   3.104 -        return PyInt_FromLong(PORT_DISCONNECT);
   3.105 +    if ( strcmp(name, "EXCEPTION") == 0 )
   3.106 +        return PyInt_FromLong(PORT_EXCEPTION);
   3.107      if ( strcmp(name, "NORMAL") == 0 )
   3.108          return PyInt_FromLong(PORT_NORMAL);
   3.109      return Py_FindMethod(xu_notifier_methods, obj, name);
     4.1 --- a/xen/common/event_channel.c	Fri Mar 26 19:57:09 2004 +0000
     4.2 +++ b/xen/common/event_channel.c	Sat Mar 27 10:20:58 2004 +0000
     4.3 @@ -154,11 +154,11 @@ static long evtchn_bind_virq(evtchn_bind
     4.4  
     4.5      /*
     4.6       * Port 0 is the fallback port for VIRQs that haven't been explicitly
     4.7 -     * bound yet. The exception is the 'error VIRQ', which is permanently 
     4.8 +     * bound yet. The exception is the 'misdirect VIRQ', which is permanently 
     4.9       * bound to port 0.
    4.10       */
    4.11      if ( ((port = p->virq_to_evtchn[virq]) != 0) ||
    4.12 -         (virq == VIRQ_ERROR) ||
    4.13 +         (virq == VIRQ_MISDIRECT) ||
    4.14           ((port = get_free_port(p)) < 0) )
    4.15          goto out;
    4.16  
    4.17 @@ -226,7 +226,7 @@ static long __evtchn_close(struct task_s
    4.18  
    4.19      chn1 = p1->event_channel;
    4.20  
    4.21 -    /* NB. Port 0 is special (VIRQ_ERROR). Never let it be closed. */
    4.22 +    /* NB. Port 0 is special (VIRQ_MISDIRECT). Never let it be closed. */
    4.23      if ( (port1 <= 0) || (port1 >= p1->max_event_channel) )
    4.24      {
    4.25          rc = -EINVAL;
    4.26 @@ -483,7 +483,7 @@ int init_event_channels(struct task_stru
    4.27      p->max_event_channel = INIT_EVENT_CHANNELS;
    4.28      memset(p->event_channel, 0, INIT_EVENT_CHANNELS * sizeof(event_channel_t));
    4.29      p->event_channel[0].state  = ECS_VIRQ;
    4.30 -    p->event_channel[0].u.virq = VIRQ_ERROR;
    4.31 +    p->event_channel[0].u.virq = VIRQ_MISDIRECT;
    4.32      return 0;
    4.33  }
    4.34  
     5.1 --- a/xen/include/hypervisor-ifs/hypervisor-if.h	Fri Mar 26 19:57:09 2004 +0000
     5.2 +++ b/xen/include/hypervisor-ifs/hypervisor-if.h	Sat Mar 27 10:20:58 2004 +0000
     5.3 @@ -56,19 +56,19 @@
     5.4   * Virtual interrupts that a guest OS may receive from the hypervisor.
     5.5   */
     5.6  
     5.7 -#define VIRQ_BLKDEV    0  /* A block device response has been queued. */
     5.8 -#define VIRQ_TIMER     1  /* A timeout has been updated. */
     5.9 -#define VIRQ_DIE       2  /* OS is about to be killed. Clean up please! */
    5.10 -#define VIRQ_DEBUG     3  /* Request guest to dump debug info (gross!) */
    5.11 -#define VIRQ_NET       4  /* There are packets for transmission. */
    5.12 -#define VIRQ_PS2       5  /* PS/2 keyboard or mouse event(s) */
    5.13 -#define VIRQ_STOP      6  /* Prepare for stopping and possible pickling */
    5.14 -#define VIRQ_EVTCHN    7  /* Event pending on an event channel */
    5.15 -#define VIRQ_VBD_UPD   8  /* Event to signal VBDs should be reprobed */
    5.16 -#define VIRQ_CONSOLE   9  /* This is only for domain-0 initial console. */
    5.17 -#define VIRQ_PHYSIRQ  10  /* Event to signal pending physical IRQs. */
    5.18 -#define VIRQ_ERROR    11  /* Catch-all virtual interrupt. */
    5.19 -#define NR_VIRQS      12
    5.20 +#define VIRQ_BLKDEV     0  /* A block device response has been queued. */
    5.21 +#define VIRQ_TIMER      1  /* A timeout has been updated. */
    5.22 +#define VIRQ_DIE        2  /* OS is about to be killed. Clean up please! */
    5.23 +#define VIRQ_DEBUG      3  /* Request guest to dump debug info (gross!) */
    5.24 +#define VIRQ_NET        4  /* There are packets for transmission. */
    5.25 +#define VIRQ_PS2        5  /* PS/2 keyboard or mouse event(s) */
    5.26 +#define VIRQ_STOP       6  /* Prepare for stopping and possible pickling */
    5.27 +#define VIRQ_EVTCHN     7  /* Event pending on an event channel */
    5.28 +#define VIRQ_VBD_UPD    8  /* Event to signal VBDs should be reprobed */
    5.29 +#define VIRQ_CONSOLE    9  /* This is only for domain-0 initial console. */
    5.30 +#define VIRQ_PHYSIRQ   10  /* Event to signal pending physical IRQs. */
    5.31 +#define VIRQ_MISDIRECT 11  /* Catch-all virtual interrupt. */
    5.32 +#define NR_VIRQS       12
    5.33  
    5.34  /*
    5.35   * MMU_XXX: specified in least 2 bits of 'ptr' field. These bits are masked
    5.36 @@ -187,23 +187,22 @@ typedef struct shared_info_st
    5.37       *  2. EXCEPTION -- notifies the domain that there has been some
    5.38       *     exceptional event associated with this channel (e.g. remote
    5.39       *     disconnect, physical IRQ error). This bit is cleared by the guest.
    5.40 +     *     A 0->1 transition of this bit will cause the PENDING bit to be set.
    5.41       *  3. MASK -- if this bit is clear then a 0->1 transition of PENDING
    5.42 -     *     or EXCEPTION will cause an asynchronous upcall to be scheduled.
    5.43 -     *     This bit is only updated by the guest. It is read-only within Xen.
    5.44 -     *     If a channel becomes pending or an exceptional event occurs while
    5.45 -     *     the channel is masked then the 'edge' is lost (i.e., when the
    5.46 -     *     channel is unmasked, the guest must manually handle pending
    5.47 -     *     notifications as no upcall will be scheduled by Xen).
    5.48 +     *     will cause an asynchronous upcall to be scheduled. This bit is only
    5.49 +     *     updated by the guest. It is read-only within Xen. If a channel
    5.50 +     *     becomes pending while the channel is masked then the 'edge' is lost
    5.51 +     *     (i.e., when the channel is unmasked, the guest must manually handle
    5.52 +     *     pending notifications as no upcall will be scheduled by Xen).
    5.53       * 
    5.54 -     * To expedite scanning of pending notifications and exceptions, any 
    5.55 -     * 0->1 transition on an unmasked channel causes a corresponding bit in
    5.56 -     * a 32-bit selector to be set. Each bit in the selector covers a 32-bit
    5.57 -     * word in the PENDING or EXCEPTION bitfield array.
    5.58 +     * To expedite scanning of pending notifications, any 0->1 pending
    5.59 +     * transition on an unmasked channel causes a corresponding bit in a
    5.60 +     * 32-bit selector to be set. Each bit in the selector covers a 32-bit
    5.61 +     * word in the PENDING bitfield array.
    5.62       */
    5.63      u32 evtchn_pending[32];
    5.64      u32 evtchn_pending_sel;
    5.65      u32 evtchn_exception[32];
    5.66 -    u32 evtchn_exception_sel;
    5.67      u32 evtchn_mask[32];
    5.68  
    5.69      /*
     6.1 --- a/xen/include/xen/event.h	Fri Mar 26 19:57:09 2004 +0000
     6.2 +++ b/xen/include/xen/event.h	Sat Mar 27 10:20:58 2004 +0000
     6.3 @@ -71,11 +71,8 @@ static inline void evtchn_set_pending(st
     6.4  
     6.5  static inline void evtchn_set_exception(struct task_struct *p, int port)
     6.6  {
     6.7 -    shared_info_t *s = p->shared_info;
     6.8 -    if ( !test_and_set_bit(port,    &s->evtchn_exception[0]) &&
     6.9 -         !test_bit        (port,    &s->evtchn_mask[0])      &&
    6.10 -         !test_and_set_bit(port>>5, &s->evtchn_exception_sel) )
    6.11 -        guest_notify(p);
    6.12 +    if ( !test_and_set_bit(port, &p->shared_info->evtchn_exception[0]) )
    6.13 +        evtchn_set_pending(p, port);
    6.14  }
    6.15  
    6.16  /*
     7.1 --- a/xenolinux-2.4.25-sparse/arch/xen/drivers/console/console.c	Fri Mar 26 19:57:09 2004 +0000
     7.2 +++ b/xenolinux-2.4.25-sparse/arch/xen/drivers/console/console.c	Sat Mar 27 10:20:58 2004 +0000
     7.3 @@ -143,8 +143,6 @@ void xen_console_init(void)
     7.4      }
     7.5  
     7.6      register_console(&kcons_info);
     7.7 -
     7.8 -    evtchn_clear_error_virq();
     7.9  }
    7.10  
    7.11  
     8.1 --- a/xenolinux-2.4.25-sparse/arch/xen/drivers/evtchn/evtchn.c	Fri Mar 26 19:57:09 2004 +0000
     8.2 +++ b/xenolinux-2.4.25-sparse/arch/xen/drivers/evtchn/evtchn.c	Sat Mar 27 10:20:58 2004 +0000
     8.3 @@ -40,35 +40,25 @@ static unsigned int ring_cons, ring_prod
     8.4  static DECLARE_WAIT_QUEUE_HEAD(evtchn_wait);
     8.5  static struct fasync_struct *evtchn_async_queue;
     8.6  
     8.7 -/*
     8.8 - * Pending normal notifications and pending exceptional notifications.
     8.9 - * 'Pending' means that we received an upcall but this is not yet ack'ed
    8.10 - * from userspace by writing to /dev/xen/evtchn.
    8.11 - */
    8.12 -static u32 pend_nrm[32], pend_exc[32];
    8.13 +/* Which ports is user-space bound to? */
    8.14 +static u32 bound_ports[32];
    8.15  
    8.16  static spinlock_t lock;
    8.17  
    8.18 -void evtchn_device_upcall(int port, int exception)
    8.19 +void evtchn_device_upcall(int port)
    8.20  {
    8.21      u16 port_subtype;
    8.22 +    shared_info_t *s = HYPERVISOR_shared_info;
    8.23  
    8.24      spin_lock(&lock);
    8.25  
    8.26      mask_evtchn(port);
    8.27 +    clear_evtchn(port);
    8.28  
    8.29 -    if ( likely(!exception) )
    8.30 -    {
    8.31 -        clear_evtchn(port);
    8.32 -        set_bit(port, &pend_nrm[0]);
    8.33 +    if ( likely(!synch_test_and_clear_bit(port, &s->evtchn_exception[0])) )
    8.34          port_subtype = PORT_NORMAL;
    8.35 -    }
    8.36      else
    8.37 -    {
    8.38 -        clear_evtchn_exception(port);
    8.39 -        set_bit(port, &pend_exc[0]);
    8.40          port_subtype = PORT_EXCEPTION;
    8.41 -    }
    8.42  
    8.43      if ( ring != NULL )
    8.44      {
    8.45 @@ -92,28 +82,8 @@ void evtchn_device_upcall(int port, int 
    8.46  
    8.47  static void __evtchn_reset_buffer_ring(void)
    8.48  {
    8.49 -    u32          m;
    8.50 -    unsigned int i, j;
    8.51 -
    8.52 -    /* Initialise the ring with currently outstanding notifications. */
    8.53 +    /* Initialise the ring to empty. Clear errors. */
    8.54      ring_cons = ring_prod = ring_overflow = 0;
    8.55 -
    8.56 -    for ( i = 0; i < 32; i++ )
    8.57 -    {
    8.58 -        m = pend_exc[i];
    8.59 -        while ( (j = ffs(m)) != 0 )
    8.60 -        {
    8.61 -            m &= ~(1 << --j);
    8.62 -            ring[ring_prod++] = (u16)(((i * 32) + j) | PORT_EXCEPTION);
    8.63 -        }
    8.64 -
    8.65 -        m = pend_nrm[i];
    8.66 -        while ( (j = ffs(m)) != 0 )
    8.67 -        {
    8.68 -            m &= ~(1 << --j);
    8.69 -            ring[ring_prod++] = (u16)(((i * 32) + j) | PORT_NORMAL);
    8.70 -        }
    8.71 -    }
    8.72  }
    8.73  
    8.74  static ssize_t evtchn_read(struct file *file, char *buf,
    8.75 @@ -232,11 +202,8 @@ static ssize_t evtchn_write(struct file 
    8.76  
    8.77      spin_lock_irq(&lock);
    8.78      for ( i = 0; i < (count/2); i++ )
    8.79 -    {
    8.80 -        clear_bit(kbuf[i]&PORTIDX_MASK, 
    8.81 -                  (kbuf[i]&PORT_EXCEPTION) ? &pend_exc[0] : &pend_nrm[0]);
    8.82 -        unmask_evtchn(kbuf[i]&PORTIDX_MASK);
    8.83 -    }
    8.84 +        if ( test_bit(kbuf[i], &bound_ports[0]) )
    8.85 +            unmask_evtchn(kbuf[i]);
    8.86      spin_unlock_irq(&lock);
    8.87  
    8.88      rc = count;
    8.89 @@ -249,14 +216,35 @@ static ssize_t evtchn_write(struct file 
    8.90  static int evtchn_ioctl(struct inode *inode, struct file *file,
    8.91                          unsigned int cmd, unsigned long arg)
    8.92  {
    8.93 -    if ( cmd != EVTCHN_RESET )
    8.94 -        return -EINVAL;
    8.95 +    int rc = 0;
    8.96 +    
    8.97 +    spin_lock_irq(&lock);
    8.98 +    
    8.99 +    switch ( cmd )
   8.100 +    {
   8.101 +    case EVTCHN_RESET:
   8.102 +        __evtchn_reset_buffer_ring();
   8.103 +        break;
   8.104 +    case EVTCHN_BIND:
   8.105 +        if ( !test_and_set_bit(arg, &bound_ports[0]) )
   8.106 +            unmask_evtchn(arg);
   8.107 +        else
   8.108 +            rc = -EINVAL;
   8.109 +        break;
   8.110 +    case EVTCHN_UNBIND:
   8.111 +        if ( test_and_clear_bit(arg, &bound_ports[0]) )
   8.112 +            mask_evtchn(arg);
   8.113 +        else
   8.114 +            rc = -EINVAL;
   8.115 +        break;
   8.116 +    default:
   8.117 +        rc = -ENOSYS;
   8.118 +        break;
   8.119 +    }
   8.120  
   8.121 -    spin_lock_irq(&lock);
   8.122 -    __evtchn_reset_buffer_ring();
   8.123      spin_unlock_irq(&lock);   
   8.124  
   8.125 -    return 0;
   8.126 +    return rc;
   8.127  }
   8.128  
   8.129  static unsigned int evtchn_poll(struct file *file, poll_table *wait)
   8.130 @@ -298,12 +286,17 @@ static int evtchn_open(struct inode *ino
   8.131  
   8.132  static int evtchn_release(struct inode *inode, struct file *filp)
   8.133  {
   8.134 +    int i;
   8.135 +
   8.136      spin_lock_irq(&lock);
   8.137      if ( ring != NULL )
   8.138      {
   8.139          free_page((unsigned long)ring);
   8.140          ring = NULL;
   8.141      }
   8.142 +    for ( i = 0; i < NR_EVENT_CHANNELS; i++ )
   8.143 +        if ( test_and_clear_bit(i, &bound_ports[0]) )
   8.144 +            mask_evtchn(i);
   8.145      spin_unlock_irq(&lock);
   8.146  
   8.147      evtchn_dev_inuse = 0;
     9.1 --- a/xenolinux-2.4.25-sparse/arch/xen/kernel/evtchn.c	Fri Mar 26 19:57:09 2004 +0000
     9.2 +++ b/xenolinux-2.4.25-sparse/arch/xen/kernel/evtchn.c	Sat Mar 27 10:20:58 2004 +0000
     9.3 @@ -38,76 +38,37 @@ static int irq_bindcount[NR_IRQS];
     9.4  /* Upcall to generic IRQ layer. */
     9.5  extern asmlinkage unsigned int do_IRQ(int irq, struct pt_regs *regs);
     9.6  
     9.7 -static void evtchn_handle_normal(shared_info_t *s, struct pt_regs *regs)
     9.8 -{
     9.9 -    unsigned long l1, l2;
    9.10 -    unsigned int  l1i, l2i, port;
    9.11 -    int           irq;
    9.12 -
    9.13 -    l1 = xchg(&s->evtchn_pending_sel, 0);
    9.14 -    while ( (l1i = ffs(l1)) != 0 )
    9.15 -    {
    9.16 -        l1i--;
    9.17 -        l1 &= ~(1 << l1i);
    9.18 -        
    9.19 -        l2 = s->evtchn_pending[l1i] & ~s->evtchn_mask[l1i];
    9.20 -        while ( (l2i = ffs(l2)) != 0 )
    9.21 -        {
    9.22 -            l2i--;
    9.23 -            l2 &= ~(1 << l2i);
    9.24 -            
    9.25 -            port = (l1i << 5) + l2i;
    9.26 -            if ( (irq = evtchn_to_irq[port]) != -1 )
    9.27 -                do_IRQ(irq, regs);
    9.28 -            else
    9.29 -                evtchn_device_upcall(port, 0);
    9.30 -        }
    9.31 -    }
    9.32 -}
    9.33 -
    9.34 -static void evtchn_handle_exceptions(shared_info_t *s, struct pt_regs *regs)
    9.35 -{
    9.36 -    unsigned long l1, l2;
    9.37 -    unsigned int  l1i, l2i, port;
    9.38 -    int           irq;
    9.39 -
    9.40 -    l1 = xchg(&s->evtchn_exception_sel, 0);
    9.41 -    while ( (l1i = ffs(l1)) != 0 )
    9.42 -    {
    9.43 -        l1i--;
    9.44 -        l1 &= ~(1 << l1i);
    9.45 -        
    9.46 -        l2 = s->evtchn_exception[l1i] & ~s->evtchn_mask[l1i];
    9.47 -        while ( (l2i = ffs(l2)) != 0 )
    9.48 -        {
    9.49 -            l2i--;
    9.50 -            l2 &= ~(1 << l2i);
    9.51 -            
    9.52 -            port = (l1i << 5) + l2i;
    9.53 -            if ( (irq = evtchn_to_irq[port]) != -1 )
    9.54 -            {
    9.55 -                printk(KERN_ALERT "Error on IRQ line %d!\n", irq);
    9.56 -                synch_clear_bit(port, &s->evtchn_exception[0]);
    9.57 -            }
    9.58 -            else
    9.59 -                evtchn_device_upcall(port, 1);
    9.60 -        }
    9.61 -    }
    9.62 -}
    9.63 -
    9.64  void evtchn_do_upcall(struct pt_regs *regs)
    9.65  {
    9.66 -    unsigned long flags;
    9.67 +    unsigned long  l1, l2;
    9.68 +    unsigned int   l1i, l2i, port;
    9.69 +    int            irq;
    9.70 +    unsigned long  flags;
    9.71      shared_info_t *s = HYPERVISOR_shared_info;
    9.72  
    9.73      local_irq_save(flags);
    9.74      
    9.75      while ( synch_test_and_clear_bit(0, &s->evtchn_upcall_pending) )
    9.76      {
    9.77 -        if ( s->evtchn_pending_sel != 0 )
    9.78 -            evtchn_handle_normal(s, regs);
    9.79 -        if ( s->evtchn_exception_sel != 0 )
    9.80 -            evtchn_handle_exceptions(s, regs);
    9.81 +        l1 = xchg(&s->evtchn_pending_sel, 0);
    9.82 +        while ( (l1i = ffs(l1)) != 0 )
    9.83 +        {
    9.84 +            l1i--;
    9.85 +            l1 &= ~(1 << l1i);
    9.86 +        
    9.87 +            l2 = s->evtchn_pending[l1i] & ~s->evtchn_mask[l1i];
    9.88 +            while ( (l2i = ffs(l2)) != 0 )
    9.89 +            {
    9.90 +                l2i--;
    9.91 +                l2 &= ~(1 << l2i);
    9.92 +            
    9.93 +                port = (l1i << 5) + l2i;
    9.94 +                if ( (irq = evtchn_to_irq[port]) != -1 )
    9.95 +                    do_IRQ(irq, regs);
    9.96 +                else
    9.97 +                    evtchn_device_upcall(port);
    9.98 +            }
    9.99 +        }
   9.100      }
   9.101  
   9.102      local_irq_restore(flags);
   9.103 @@ -346,16 +307,16 @@ static struct hw_interrupt_type pirq_typ
   9.104      NULL
   9.105  };
   9.106  
   9.107 -static void error_interrupt(int irq, void *dev_id, struct pt_regs *regs)
   9.108 +static void misdirect_interrupt(int irq, void *dev_id, struct pt_regs *regs)
   9.109  {
   9.110 -    printk(KERN_ALERT "unexpected VIRQ_ERROR trap to vector %d\n", irq);
   9.111 +    /* nothing */
   9.112  }
   9.113  
   9.114 -static struct irqaction error_action = {
   9.115 -    error_interrupt, 
   9.116 +static struct irqaction misdirect_action = {
   9.117 +    misdirect_interrupt, 
   9.118      SA_INTERRUPT, 
   9.119      0, 
   9.120 -    "error", 
   9.121 +    "misdirect", 
   9.122      NULL, 
   9.123      NULL
   9.124  };
   9.125 @@ -372,7 +333,10 @@ void __init init_IRQ(void)
   9.126  
   9.127      /* No event-channel -> IRQ mappings. */
   9.128      for ( i = 0; i < NR_EVENT_CHANNELS; i++ )
   9.129 +    {
   9.130          evtchn_to_irq[i] = -1;
   9.131 +        mask_evtchn(i); /* No event channels are 'live' right now. */
   9.132 +    }
   9.133  
   9.134      /* No IRQ -> event-channel mappings. */
   9.135      for ( i = 0; i < NR_IRQS; i++ )
   9.136 @@ -400,5 +364,5 @@ void __init init_IRQ(void)
   9.137          irq_desc[pirq_to_irq(i)].handler = &pirq_type;
   9.138      }
   9.139  
   9.140 -    (void)setup_irq(bind_virq_to_irq(VIRQ_ERROR), &error_action);
   9.141 +    (void)setup_irq(bind_virq_to_irq(VIRQ_MISDIRECT), &misdirect_action);
   9.142  }
    10.1 --- a/xenolinux-2.4.25-sparse/include/asm-xen/evtchn.h	Fri Mar 26 19:57:09 2004 +0000
    10.2 +++ b/xenolinux-2.4.25-sparse/include/asm-xen/evtchn.h	Sat Mar 27 10:20:58 2004 +0000
    10.3 @@ -23,7 +23,7 @@
    10.4  void evtchn_do_upcall(struct pt_regs *regs);
    10.5  
    10.6  /* Entry point for notifications into the userland character device. */
    10.7 -void evtchn_device_upcall(int port, int exception);
    10.8 +void evtchn_device_upcall(int port);
    10.9  
   10.10  static inline void mask_evtchn(int port)
   10.11  {
   10.12 @@ -34,7 +34,6 @@ static inline void mask_evtchn(int port)
   10.13  static inline void unmask_evtchn(int port)
   10.14  {
   10.15      shared_info_t *s = HYPERVISOR_shared_info;
   10.16 -    int need_upcall = 0;
   10.17  
   10.18      synch_clear_bit(port, &s->evtchn_mask[0]);
   10.19  
   10.20 @@ -42,19 +41,8 @@ static inline void unmask_evtchn(int por
   10.21       * The following is basically the equivalent of 'hw_resend_irq'. Just like
   10.22       * a real IO-APIC we 'lose the interrupt edge' if the channel is masked.
   10.23       */
   10.24 -
   10.25 -    /* Asserted a standard notification? */
   10.26      if (  synch_test_bit        (port,    &s->evtchn_pending[0]) && 
   10.27 -         !synch_test_and_set_bit(port>>5, &s->evtchn_pending_sel) )
   10.28 -        need_upcall = 1;
   10.29 -
   10.30 -    /* Asserted an exceptional notification? */
   10.31 -    if (  synch_test_bit        (port,    &s->evtchn_exception[0]) && 
   10.32 -         !synch_test_and_set_bit(port>>5, &s->evtchn_exception_sel) )
   10.33 -        need_upcall = 1;
   10.34 -
   10.35 -    /* If asserted either type of notification, check the master flags. */
   10.36 -    if ( need_upcall &&
   10.37 +         !synch_test_and_set_bit(port>>5, &s->evtchn_pending_sel) &&
   10.38           !synch_test_and_set_bit(0,       &s->evtchn_upcall_pending) &&
   10.39           !synch_test_bit        (0,       &s->evtchn_upcall_mask) )
   10.40          evtchn_do_upcall(NULL);
   10.41 @@ -72,16 +60,6 @@ static inline void clear_evtchn_exceptio
   10.42      synch_clear_bit(port, &s->evtchn_exception[0]);
   10.43  }
   10.44  
   10.45 -static inline void evtchn_clear_error_virq(void)
   10.46 -{
   10.47 -    /*
   10.48 -     * XXX This prevents a bogus 'VIRQ_ERROR' when interrupts are enabled
   10.49 -     * for the first time. This works because by this point all important
   10.50 -     * VIRQs (eg. timer) have been properly bound.
   10.51 -     */
   10.52 -    synch_clear_bit(0, &HYPERVISOR_shared_info->evtchn_pending[0]);
   10.53 -}
   10.54 -
   10.55  /*
   10.56   * CHARACTER-DEVICE DEFINITIONS
   10.57   */
   10.58 @@ -95,6 +73,10 @@ static inline void evtchn_clear_error_vi
   10.59  
   10.60  /* /dev/xen/evtchn ioctls: */
   10.61  /* EVTCHN_RESET: Clear and reinit the event buffer. Clear error condition. */
   10.62 -#define EVTCHN_RESET _IO('E', 1)
   10.63 +#define EVTCHN_RESET  _IO('E', 1)
   10.64 +/* EVTCHN_BIND: Bind to teh specified event-channel port. */
   10.65 +#define EVTCHN_BIND   _IO('E', 2)
   10.66 +/* EVTCHN_UNBIND: Unbind from the specified event-channel port. */
   10.67 +#define EVTCHN_UNBIND _IO('E', 3)
   10.68  
   10.69  #endif /* __ASM_EVTCHN_H__ */