aboutsummaryrefslogtreecommitdiffstats
path: root/netbsd-2.0-xen-sparse
diff options
context:
space:
mode:
authorcl349@labyrinth.cl.cam.ac.uk <cl349@labyrinth.cl.cam.ac.uk>2004-09-06 19:07:17 +0000
committercl349@labyrinth.cl.cam.ac.uk <cl349@labyrinth.cl.cam.ac.uk>2004-09-06 19:07:17 +0000
commit31ae3c19a87731b8cc5831a800025ccb9594a85c (patch)
tree3b6d8c6d0dcae42bd59acbc196527c6880ceff7d /netbsd-2.0-xen-sparse
parent3ebb973d5045b339b449ecd3cd06cde2b00cafee (diff)
downloadxen-31ae3c19a87731b8cc5831a800025ccb9594a85c.tar.gz
xen-31ae3c19a87731b8cc5831a800025ccb9594a85c.tar.bz2
xen-31ae3c19a87731b8cc5831a800025ccb9594a85c.zip
bitkeeper revision 1.1159.72.3 (413cb565kAu26gtMpvumani1Zx6Vjw)
Add new files in NetBSD for Xen2.0.
Diffstat (limited to 'netbsd-2.0-xen-sparse')
-rw-r--r--netbsd-2.0-xen-sparse/sys/arch/xen/include/ctrl_if.h138
-rw-r--r--netbsd-2.0-xen-sparse/sys/arch/xen/include/evtchn.h53
-rw-r--r--netbsd-2.0-xen-sparse/sys/arch/xen/xen/ctrl_if.c573
-rw-r--r--netbsd-2.0-xen-sparse/sys/arch/xen/xen/evtchn.c347
4 files changed, 1111 insertions, 0 deletions
diff --git a/netbsd-2.0-xen-sparse/sys/arch/xen/include/ctrl_if.h b/netbsd-2.0-xen-sparse/sys/arch/xen/include/ctrl_if.h
new file mode 100644
index 0000000000..6d6bfe172f
--- /dev/null
+++ b/netbsd-2.0-xen-sparse/sys/arch/xen/include/ctrl_if.h
@@ -0,0 +1,138 @@
+/******************************************************************************
+ * ctrl_if.h
+ *
+ * Management functions for special interface to the domain controller.
+ *
+ * Copyright (c) 2004, K A Fraser
+ */
+
+#ifndef __ASM_XEN__CTRL_IF_H__
+#define __ASM_XEN__CTRL_IF_H__
+
+typedef control_msg_t ctrl_msg_t;
+
+/*
+ * Callback function type. Called for asynchronous processing of received
+ * request messages, and responses to previously-transmitted request messages.
+ * The parameters are (@msg, @id).
+ * @msg: Original request/response message (not a copy). The message can be
+ * modified in-place by the handler (e.g., a response callback can
+ * turn a request message into a response message in place). The message
+ * is no longer accessible after the callback handler returns -- if the
+ * message is required to persist for longer then it must be copied.
+ * @id: (Response callbacks only) The 'id' that was specified when the
+ * original request message was queued for transmission.
+ */
+typedef void (*ctrl_msg_handler_t)(ctrl_msg_t *, unsigned long);
+
+/*
+ * Send @msg to the domain controller. Execute @hnd when a response is
+ * received, passing the response message and the specified @id. This
+ * operation will not block: it will return -EAGAIN if there is no space.
+ * Notes:
+ * 1. The @msg is copied if it is transmitted and so can be freed after this
+ * function returns.
+ * 2. If @hnd is NULL then no callback is executed.
+ */
+int
+ctrl_if_send_message_noblock(
+ ctrl_msg_t *msg,
+ ctrl_msg_handler_t hnd,
+ unsigned long id);
+
+/*
+ * Send @msg to the domain controller. Execute @hnd when a response is
+ * received, passing the response message and the specified @id. This
+ * operation will block until the message is sent, or a signal is received
+ * for the calling process (unless @wait_state is TASK_UNINTERRUPTIBLE).
+ * Notes:
+ * 1. The @msg is copied if it is transmitted and so can be freed after this
+ * function returns.
+ * 2. If @hnd is NULL then no callback is executed.
+ */
+int
+ctrl_if_send_message_block(
+ ctrl_msg_t *msg,
+ ctrl_msg_handler_t hnd,
+ unsigned long id,
+ long wait_state);
+
+/*
+ * Send @msg to the domain controller. Block until the response is received,
+ * and then copy it into the provided buffer, @rmsg.
+ */
+int
+ctrl_if_send_message_and_get_response(
+ ctrl_msg_t *msg,
+ ctrl_msg_t *rmsg,
+ long wait_state);
+
+#ifdef notyet
+/*
+ * Request a callback when there is /possibly/ space to immediately send a
+ * message to the domain controller. This function returns 0 if there is
+ * already space to trasnmit a message --- in this case the callback task /may/
+ * still be executed. If this function returns 1 then the callback /will/ be
+ * executed when space becomes available.
+ */
+int
+ctrl_if_enqueue_space_callback(
+ struct tq_struct *task);
+#endif
+
+/*
+ * Send a response (@msg) to a message from the domain controller. This will
+ * never block.
+ * Notes:
+ * 1. The @msg is copied and so can be freed after this function returns.
+ * 2. The @msg may be the original request message, modified in-place.
+ */
+void
+ctrl_if_send_response(
+ ctrl_msg_t *msg);
+
+/*
+ * Register a receiver for typed messages from the domain controller. The
+ * handler (@hnd) is called for every received message of specified @type.
+ * Returns TRUE (non-zero) if the handler was successfully registered.
+ * If CALLBACK_IN_BLOCKING CONTEXT is specified in @flags then callbacks will
+ * occur in a context in which it is safe to yield (i.e., process context).
+ */
+#define CALLBACK_IN_BLOCKING_CONTEXT 1
+int ctrl_if_register_receiver(
+ uint8_t type,
+ ctrl_msg_handler_t hnd,
+ unsigned int flags);
+
+/*
+ * Unregister a receiver for typed messages from the domain controller. The
+ * handler (@hnd) will not be executed after this function returns.
+ */
+void
+ctrl_if_unregister_receiver(
+ uint8_t type, ctrl_msg_handler_t hnd);
+
+/* Suspend/resume notifications. */
+void ctrl_if_suspend(void);
+void ctrl_if_resume(void);
+
+/* Start-of-day setup. */
+void ctrl_if_init(void);
+
+/*
+ * Returns TRUE if there are no outstanding message requests at the domain
+ * controller. This can be used to ensure that messages have really flushed
+ * through when it is not possible to use the response-callback interface.
+ * WARNING: If other subsystems are using the control interface then this
+ * function might never return TRUE!
+ */
+int ctrl_if_transmitter_empty(void); /* !! DANGEROUS FUNCTION !! */
+
+/*
+ * Manually discard response messages from the domain controller.
+ * WARNING: This is usually done automatically -- this function should only
+ * be called when normal interrupt mechanisms are disabled!
+ */
+void ctrl_if_discard_responses(void); /* !! DANGEROUS FUNCTION !! */
+
+#endif /* __ASM_XEN__CONTROL_IF_H__ */
diff --git a/netbsd-2.0-xen-sparse/sys/arch/xen/include/evtchn.h b/netbsd-2.0-xen-sparse/sys/arch/xen/include/evtchn.h
new file mode 100644
index 0000000000..5dd98ef250
--- /dev/null
+++ b/netbsd-2.0-xen-sparse/sys/arch/xen/include/evtchn.h
@@ -0,0 +1,53 @@
+/* $NetBSD$ */
+
+/*
+ *
+ * Copyright (c) 2004 Christian Limpach.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Christian Limpach.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _XEN_EVENTS_H_
+#define _XEN_EVENTS_H_
+
+#define NR_IRQS 32
+
+extern int evtchn_to_irq[];
+
+/* typedef unsigned int (*ev_handler_t)(int, struct pt_regs *); */
+typedef int (*ev_handler_t)(void *);
+
+void events_default_setup(void);
+void init_events(void);
+unsigned int do_event(int, struct trapframe *);
+int event_set_handler(int, ev_handler_t, void *, int);
+
+int bind_virq_to_irq(int);
+void unbind_virq_from_irq(int);
+int bind_evtchn_to_irq(int);
+
+#endif /* _XEN_EVENTS_H_ */
diff --git a/netbsd-2.0-xen-sparse/sys/arch/xen/xen/ctrl_if.c b/netbsd-2.0-xen-sparse/sys/arch/xen/xen/ctrl_if.c
new file mode 100644
index 0000000000..39b4febdd3
--- /dev/null
+++ b/netbsd-2.0-xen-sparse/sys/arch/xen/xen/ctrl_if.c
@@ -0,0 +1,573 @@
+/******************************************************************************
+ * ctrl_if.c
+ *
+ * Management functions for special interface to the domain controller.
+ *
+ * Copyright (c) 2004, K A Fraser
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/malloc.h>
+#include <sys/kthread.h>
+
+#include <machine/xen.h>
+#include <machine/hypervisor.h>
+#include <machine/ctrl_if.h>
+#include <machine/evtchn.h>
+
+#if 0
+#define DPRINTK(_f, _a...) printf("(file=%s, line=%d) " _f, \
+ __FILE__ , __LINE__ , ## _a )
+#else
+#define DPRINTK(_f, _a...) ((void)0)
+#endif
+
+/*
+ * Only used by initial domain which must create its own control-interface
+ * event channel. This value is picked up by the user-space domain controller
+ * via an ioctl.
+ */
+int initdom_ctrlif_domcontroller_port = -1;
+
+static int ctrl_if_evtchn;
+static int ctrl_if_irq;
+static struct simplelock ctrl_if_lock;
+
+static CONTROL_RING_IDX ctrl_if_tx_resp_cons;
+static CONTROL_RING_IDX ctrl_if_rx_req_cons;
+
+/* Incoming message requests. */
+ /* Primary message type -> message handler. */
+static ctrl_msg_handler_t ctrl_if_rxmsg_handler[256];
+ /* Primary message type -> callback in process context? */
+static unsigned long ctrl_if_rxmsg_blocking_context[256/sizeof(unsigned long)];
+#if 0
+ /* Is it late enough during bootstrap to use schedule_task()? */
+static int safe_to_schedule_task;
+#endif
+ /* Queue up messages to be handled in process context. */
+static ctrl_msg_t ctrl_if_rxmsg_deferred[CONTROL_RING_SIZE];
+static CONTROL_RING_IDX ctrl_if_rxmsg_deferred_prod;
+static CONTROL_RING_IDX ctrl_if_rxmsg_deferred_cons;
+
+/* Incoming message responses: message identifier -> message handler/id. */
+static struct {
+ ctrl_msg_handler_t fn;
+ unsigned long id;
+} ctrl_if_txmsg_id_mapping[CONTROL_RING_SIZE];
+
+/* For received messages that must be deferred to process context. */
+static void __ctrl_if_rxmsg_deferred(void *unused);
+
+#ifdef notyet
+/* Deferred callbacks for people waiting for space in the transmit ring. */
+static int DECLARE_TASK_QUEUE(ctrl_if_tx_tq);
+#endif
+
+static void *ctrl_if_softintr = NULL;
+
+static int ctrl_if_tx_wait;
+static void __ctrl_if_tx_tasklet(unsigned long data);
+
+static void __ctrl_if_rx_tasklet(unsigned long data);
+
+static void ctrl_if_kthread(void *);
+
+#define get_ctrl_if() ((control_if_t *)((char *)HYPERVISOR_shared_info + 2048))
+#define TX_FULL(_c) \
+ (((_c)->tx_req_prod - ctrl_if_tx_resp_cons) == CONTROL_RING_SIZE)
+
+static void ctrl_if_notify_controller(void)
+{
+ hypervisor_notify_via_evtchn(ctrl_if_evtchn);
+}
+
+static void ctrl_if_rxmsg_default_handler(ctrl_msg_t *msg, unsigned long id)
+{
+ msg->length = 0;
+ ctrl_if_send_response(msg);
+}
+
+static void __ctrl_if_tx_tasklet(unsigned long data)
+{
+ control_if_t *ctrl_if = get_ctrl_if();
+ ctrl_msg_t *msg;
+ int was_full = TX_FULL(ctrl_if);
+ CONTROL_RING_IDX rp;
+
+ rp = ctrl_if->tx_resp_prod;
+ __insn_barrier(); /* Ensure we see all requests up to 'rp'. */
+
+ while ( ctrl_if_tx_resp_cons != rp )
+ {
+ msg = &ctrl_if->tx_ring[MASK_CONTROL_IDX(ctrl_if_tx_resp_cons)];
+
+ DPRINTK("Rx-Rsp %u/%u :: %d/%d\n",
+ ctrl_if_tx_resp_cons,
+ ctrl_if->tx_resp_prod,
+ msg->type, msg->subtype);
+
+ /* Execute the callback handler, if one was specified. */
+ if ( msg->id != 0xFF )
+ {
+ (*ctrl_if_txmsg_id_mapping[msg->id].fn)(
+ msg, ctrl_if_txmsg_id_mapping[msg->id].id);
+ __insn_barrier(); /* Execute, /then/ free. */
+ ctrl_if_txmsg_id_mapping[msg->id].fn = NULL;
+ }
+
+ /*
+ * Step over the message in the ring /after/ finishing reading it. As
+ * soon as the index is updated then the message may get blown away.
+ */
+ __insn_barrier();
+ ctrl_if_tx_resp_cons++;
+ }
+
+ if ( was_full && !TX_FULL(ctrl_if) )
+ {
+ wakeup(&ctrl_if_tx_wait);
+#ifdef notyet
+ run_task_queue(&ctrl_if_tx_tq);
+#endif
+ }
+}
+
+static void __ctrl_if_rxmsg_deferred(void *unused)
+{
+ ctrl_msg_t *msg;
+ CONTROL_RING_IDX dp;
+
+ dp = ctrl_if_rxmsg_deferred_prod;
+ __insn_barrier(); /* Ensure we see all deferred requests up to 'dp'. */
+
+ while ( ctrl_if_rxmsg_deferred_cons != dp )
+ {
+ msg = &ctrl_if_rxmsg_deferred[MASK_CONTROL_IDX(
+ ctrl_if_rxmsg_deferred_cons++)];
+ (*ctrl_if_rxmsg_handler[msg->type])(msg, 0);
+ }
+}
+
+static void __ctrl_if_rx_tasklet(unsigned long data)
+{
+ control_if_t *ctrl_if = get_ctrl_if();
+ ctrl_msg_t msg, *pmsg;
+ CONTROL_RING_IDX rp, dp;
+
+ dp = ctrl_if_rxmsg_deferred_prod;
+ rp = ctrl_if->rx_req_prod;
+ __insn_barrier(); /* Ensure we see all requests up to 'rp'. */
+
+ while ( ctrl_if_rx_req_cons != rp )
+ {
+ pmsg = &ctrl_if->rx_ring[MASK_CONTROL_IDX(ctrl_if_rx_req_cons++)];
+ memcpy(&msg, pmsg, offsetof(ctrl_msg_t, msg));
+
+ DPRINTK("Rx-Req %u/%u :: %d/%d\n",
+ ctrl_if_rx_req_cons-1,
+ ctrl_if->rx_req_prod,
+ msg.type, msg.subtype);
+
+ if ( msg.length != 0 )
+ memcpy(msg.msg, pmsg->msg, msg.length);
+
+ if ( x86_atomic_test_bit(
+ (unsigned long *)&ctrl_if_rxmsg_blocking_context,
+ msg.type) )
+ memcpy(&ctrl_if_rxmsg_deferred[MASK_CONTROL_IDX(dp++)],
+ &msg, offsetof(ctrl_msg_t, msg) + msg.length);
+ else
+ (*ctrl_if_rxmsg_handler[msg.type])(&msg, 0);
+ }
+
+ if ( dp != ctrl_if_rxmsg_deferred_prod )
+ {
+ __insn_barrier();
+ ctrl_if_rxmsg_deferred_prod = dp;
+#if 0
+ wakeup(&ctrl_if_kthread);
+#else
+ if (ctrl_if_softintr)
+ softintr_schedule(ctrl_if_softintr);
+#endif
+ }
+}
+
+static int ctrl_if_interrupt(void *arg)
+{
+ control_if_t *ctrl_if = get_ctrl_if();
+
+ if ( ctrl_if_tx_resp_cons != ctrl_if->tx_resp_prod ||
+ ctrl_if_rx_req_cons != ctrl_if->rx_req_prod ) {
+#if 0
+ wakeup(&ctrl_if_kthread);
+#else
+ if (ctrl_if_softintr)
+ softintr_schedule(ctrl_if_softintr);
+#endif
+ }
+
+ return 0;
+}
+
+int
+ctrl_if_send_message_noblock(
+ ctrl_msg_t *msg,
+ ctrl_msg_handler_t hnd,
+ unsigned long id)
+{
+ control_if_t *ctrl_if = get_ctrl_if();
+ unsigned long flags;
+ int i;
+
+ save_and_cli(flags);
+ simple_lock(&ctrl_if_lock);
+
+ if ( TX_FULL(ctrl_if) )
+ {
+ simple_unlock(&ctrl_if_lock);
+ restore_flags(flags);
+ return -EAGAIN;
+ }
+
+ msg->id = 0xFF;
+ if ( hnd != NULL )
+ {
+ for ( i = 0; ctrl_if_txmsg_id_mapping[i].fn != NULL; i++ )
+ continue;
+ ctrl_if_txmsg_id_mapping[i].fn = hnd;
+ ctrl_if_txmsg_id_mapping[i].id = id;
+ msg->id = i;
+ }
+
+ DPRINTK("Tx-Req %u/%u :: %d/%d\n",
+ ctrl_if->tx_req_prod,
+ ctrl_if_tx_resp_cons,
+ msg->type, msg->subtype);
+
+ memcpy(&ctrl_if->tx_ring[MASK_CONTROL_IDX(ctrl_if->tx_req_prod)],
+ msg, sizeof(*msg));
+ __insn_barrier(); /* Write the message before letting the controller peek at it. */
+ ctrl_if->tx_req_prod++;
+
+ simple_unlock(&ctrl_if_lock);
+ restore_flags(flags);
+
+ ctrl_if_notify_controller();
+
+ return 0;
+}
+
+int
+ctrl_if_send_message_block(
+ ctrl_msg_t *msg,
+ ctrl_msg_handler_t hnd,
+ unsigned long id,
+ long wait_state)
+{
+ int rc;
+
+ while ((rc = ctrl_if_send_message_noblock(msg, hnd, id)) == EAGAIN) {
+ /* XXXcl possible race -> add a lock and ltsleep */
+ rc = tsleep((caddr_t) &ctrl_if_tx_wait, PUSER | PCATCH,
+ "ctrl_if", 0);
+ if (rc)
+ break;
+ }
+
+ return rc;
+}
+
+/* Allow a reponse-callback handler to find context of a blocked requester. */
+struct rsp_wait {
+ ctrl_msg_t *msg; /* Buffer for the response message. */
+ struct task_struct *task; /* The task that is blocked on the response. */
+ int done; /* Indicate to 'task' that response is rcv'ed. */
+};
+
+static void __ctrl_if_get_response(ctrl_msg_t *msg, unsigned long id)
+{
+ struct rsp_wait *wait = (struct rsp_wait *)id;
+
+ memcpy(wait->msg, msg, sizeof(*msg));
+ __insn_barrier();
+ wait->done = 1;
+
+ wakeup(wait);
+}
+
+int
+ctrl_if_send_message_and_get_response(
+ ctrl_msg_t *msg,
+ ctrl_msg_t *rmsg,
+ long wait_state)
+{
+ struct rsp_wait wait;
+ int rc;
+
+ wait.msg = rmsg;
+ wait.done = 0;
+
+ if ( (rc = ctrl_if_send_message_block(msg, __ctrl_if_get_response,
+ (unsigned long)&wait,
+ wait_state)) != 0 )
+ return rc;
+
+ for ( ; ; )
+ {
+ if ( wait.done )
+ break;
+ tsleep((caddr_t)&wait, PUSER | PCATCH, "ctrl_if", 0);
+ }
+
+ return 0;
+}
+
+#ifdef notyet
+int
+ctrl_if_enqueue_space_callback(
+ struct tq_struct *task)
+{
+ control_if_t *ctrl_if = get_ctrl_if();
+
+ /* Fast path. */
+ if ( !TX_FULL(ctrl_if) )
+ return 0;
+
+ (void)queue_task(task, &ctrl_if_tx_tq);
+
+ /*
+ * We may race execution of the task queue, so return re-checked status. If
+ * the task is not executed despite the ring being non-full then we will
+ * certainly return 'not full'.
+ */
+ __insn_barrier();
+ return TX_FULL(ctrl_if);
+}
+#endif
+
+void
+ctrl_if_send_response(
+ ctrl_msg_t *msg)
+{
+ control_if_t *ctrl_if = get_ctrl_if();
+ unsigned long flags;
+ ctrl_msg_t *dmsg;
+
+ /*
+ * NB. The response may the original request message, modified in-place.
+ * In this situation we may have src==dst, so no copying is required.
+ */
+ save_and_cli(flags);
+ simple_lock(&ctrl_if_lock);
+
+ DPRINTK("Tx-Rsp %u :: %d/%d\n",
+ ctrl_if->rx_resp_prod,
+ msg->type, msg->subtype);
+
+ dmsg = &ctrl_if->rx_ring[MASK_CONTROL_IDX(ctrl_if->rx_resp_prod)];
+ if ( dmsg != msg )
+ memcpy(dmsg, msg, sizeof(*msg));
+
+ __insn_barrier(); /* Write the message before letting the controller peek at it. */
+ ctrl_if->rx_resp_prod++;
+
+ simple_unlock(&ctrl_if_lock);
+ restore_flags(flags);
+
+ ctrl_if_notify_controller();
+}
+
+int
+ctrl_if_register_receiver(
+ uint8_t type,
+ ctrl_msg_handler_t hnd,
+ unsigned int flags)
+{
+ unsigned long _flags;
+ int inuse;
+
+ save_and_cli(_flags);
+ simple_lock(&ctrl_if_lock);
+
+ inuse = (ctrl_if_rxmsg_handler[type] != ctrl_if_rxmsg_default_handler);
+
+ if ( inuse )
+ {
+ printf("Receiver %p already established for control "
+ "messages of type %d.\n", ctrl_if_rxmsg_handler[type], type);
+ }
+ else
+ {
+ ctrl_if_rxmsg_handler[type] = hnd;
+ x86_atomic_clear_bit((unsigned long *)&ctrl_if_rxmsg_blocking_context, type);
+ if ( flags == CALLBACK_IN_BLOCKING_CONTEXT )
+ {
+ x86_atomic_set_bit((unsigned long *)&ctrl_if_rxmsg_blocking_context, type);
+#if 0
+ if ( !safe_to_schedule_task )
+ BUG();
+#endif
+ }
+ }
+
+ simple_unlock(&ctrl_if_lock);
+ restore_flags(_flags);
+
+ return !inuse;
+}
+
+void
+ctrl_if_unregister_receiver(
+ uint8_t type,
+ ctrl_msg_handler_t hnd)
+{
+ unsigned long flags;
+
+ save_and_cli(flags);
+ simple_lock(&ctrl_if_lock);
+
+ if ( ctrl_if_rxmsg_handler[type] != hnd )
+ printf("Receiver %p is not registered for control "
+ "messages of type %d.\n", hnd, type);
+ else
+ ctrl_if_rxmsg_handler[type] = ctrl_if_rxmsg_default_handler;
+
+ simple_unlock(&ctrl_if_lock);
+ restore_flags(flags);
+
+ /* Ensure that @hnd will not be executed after this function returns. */
+#if 0
+ wakeup(&ctrl_if_kthread);
+#else
+ if (ctrl_if_softintr)
+ softintr_schedule(ctrl_if_softintr);
+#endif
+}
+
+static void
+ctrl_if_kthread(void *arg)
+{
+ control_if_t *ctrl_if = get_ctrl_if();
+
+ // printf("ctrl_if_kthread starting\n");
+ for (;;) {
+ if ( ctrl_if_tx_resp_cons != ctrl_if->tx_resp_prod )
+ __ctrl_if_tx_tasklet(0);
+
+ if ( ctrl_if_rx_req_cons != ctrl_if->rx_req_prod )
+ __ctrl_if_rx_tasklet(0);
+
+ if ( ctrl_if_rxmsg_deferred_cons !=
+ ctrl_if_rxmsg_deferred_prod )
+ __ctrl_if_rxmsg_deferred(NULL);
+
+ if (arg) {
+ // printf("ctrl_if_kthread one-shot done\n");
+ return;
+ }
+
+ tsleep((caddr_t)&ctrl_if_kthread, PUSER | PCATCH,
+ "ctrl_if", 0);
+ }
+}
+
+static void
+ctrl_if_create_kthread(void *arg)
+{
+
+ printf("ctrl_if_kthread creating\n");
+ if (kthread_create1(ctrl_if_kthread, arg, NULL, "ctrl_if"))
+ printf("ctrl_if_kthread create failed\n");
+ softintr_schedule(ctrl_if_softintr);
+}
+
+#ifdef notyet
+void ctrl_if_suspend(void)
+{
+ free_irq(ctrl_if_irq, NULL);
+ unbind_evtchn_from_irq(ctrl_if_evtchn);
+}
+#endif
+
+void ctrl_if_resume(void)
+{
+ control_if_t *ctrl_if = get_ctrl_if();
+
+ if ( xen_start_info.flags & SIF_INITDOMAIN )
+ {
+ /*
+ * The initial domain must create its own domain-controller link.
+ * The controller is probably not running at this point, but will
+ * pick up its end of the event channel from
+ */
+ evtchn_op_t op;
+ op.cmd = EVTCHNOP_bind_interdomain;
+ op.u.bind_interdomain.dom1 = DOMID_SELF;
+ op.u.bind_interdomain.dom2 = DOMID_SELF;
+ if ( HYPERVISOR_event_channel_op(&op) != 0 )
+ panic("EVTCHNOP_bind_interdomain");
+ xen_start_info.domain_controller_evtchn = op.u.bind_interdomain.port1;
+ initdom_ctrlif_domcontroller_port = op.u.bind_interdomain.port2;
+ }
+
+ /* Sync up with shared indexes. */
+ ctrl_if_tx_resp_cons = ctrl_if->tx_resp_prod;
+ ctrl_if_rx_req_cons = ctrl_if->rx_resp_prod;
+
+ ctrl_if_evtchn = xen_start_info.domain_controller_evtchn;
+ ctrl_if_irq = bind_evtchn_to_irq(ctrl_if_evtchn);
+
+ event_set_handler(ctrl_if_irq, &ctrl_if_interrupt, NULL, IPL_HIGH);
+ hypervisor_enable_irq(ctrl_if_irq);
+}
+
+void ctrl_if_init(void)
+{
+ int i;
+
+ for ( i = 0; i < 256; i++ )
+ ctrl_if_rxmsg_handler[i] = ctrl_if_rxmsg_default_handler;
+
+ simple_lock_init(&ctrl_if_lock);
+
+ if (0) kthread_create(ctrl_if_create_kthread, NULL);
+ ctrl_if_softintr =
+ softintr_establish(IPL_SOFTNET, ctrl_if_kthread, (void *)1);
+
+ ctrl_if_resume();
+}
+
+
+#if 0
+/* This is called after it is safe to call schedule_task(). */
+static int __init ctrl_if_late_setup(void)
+{
+ safe_to_schedule_task = 1;
+ return 0;
+}
+__initcall(ctrl_if_late_setup);
+#endif
+
+
+/*
+ * !! The following are DANGEROUS FUNCTIONS !!
+ * Use with care [for example, see xencons_force_flush()].
+ */
+
+int ctrl_if_transmitter_empty(void)
+{
+ return (get_ctrl_if()->tx_req_prod == ctrl_if_tx_resp_cons);
+}
+
+void ctrl_if_discard_responses(void)
+{
+ ctrl_if_tx_resp_cons = get_ctrl_if()->tx_resp_prod;
+}
+
diff --git a/netbsd-2.0-xen-sparse/sys/arch/xen/xen/evtchn.c b/netbsd-2.0-xen-sparse/sys/arch/xen/xen/evtchn.c
new file mode 100644
index 0000000000..ca3f7c99f6
--- /dev/null
+++ b/netbsd-2.0-xen-sparse/sys/arch/xen/xen/evtchn.c
@@ -0,0 +1,347 @@
+/* $NetBSD$ */
+
+/*
+ *
+ * Copyright (c) 2004 Christian Limpach.
+ * Copyright (c) 2004, K A Fraser.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Christian Limpach.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/malloc.h>
+#include <sys/reboot.h>
+
+#include <uvm/uvm.h>
+
+#include <machine/intrdefs.h>
+
+#include <machine/xen.h>
+#include <machine/hypervisor.h>
+#include <machine/evtchn.h>
+#include <machine/ctrl_if.h>
+#include <machine/xenfunc.h>
+
+struct pic xenev_pic = {
+ .pic_dev = {
+ .dv_xname = "xen_fakepic",
+ },
+ .pic_type = PIC_XEN,
+ .pic_lock = __SIMPLELOCK_UNLOCKED,
+};
+
+/*
+ * This lock protects updates to the following mapping and reference-count
+ * arrays. The lock does not need to be acquired to read the mapping tables.
+ */
+static struct simplelock irq_mapping_update_lock = SIMPLELOCK_INITIALIZER;
+
+/* IRQ <-> event-channel mappings. */
+int evtchn_to_irq[NR_EVENT_CHANNELS];
+int irq_to_evtchn[NR_IRQS];
+
+/* IRQ <-> VIRQ mapping. */
+static int virq_to_irq[NR_VIRQS];
+
+/* Reference counts for bindings to IRQs. */
+static int irq_bindcount[NR_IRQS];
+
+#if 0
+static int xen_die_handler(void *);
+#endif
+static int xen_debug_handler(void *);
+static int xen_misdirect_handler(void *);
+
+void
+events_default_setup()
+{
+ int i;
+
+ /* No VIRQ -> IRQ mappings. */
+ for (i = 0; i < NR_VIRQS; i++)
+ virq_to_irq[i] = -1;
+
+ /* No event-channel -> IRQ mappings. */
+ for (i = 0; i < NR_EVENT_CHANNELS; i++) {
+ evtchn_to_irq[i] = -1;
+ hypervisor_mask_event(i); /* No event channels are 'live' right now. */
+ }
+
+ /* No IRQ -> event-channel mappings. */
+ for (i = 0; i < NR_IRQS; i++)
+ irq_to_evtchn[i] = -1;
+}
+
+void
+init_events()
+{
+ int irq;
+
+ irq = bind_virq_to_irq(VIRQ_DEBUG);
+ event_set_handler(irq, &xen_debug_handler, NULL, IPL_DEBUG);
+ hypervisor_enable_irq(irq);
+
+ irq = bind_virq_to_irq(VIRQ_MISDIRECT);
+ event_set_handler(irq, &xen_misdirect_handler, NULL, IPL_DIE);
+ hypervisor_enable_irq(irq);
+
+ /* This needs to be done early, but after the IRQ subsystem is
+ * alive. */
+ ctrl_if_init();
+
+ enable_intr(); /* at long last... */
+}
+
+unsigned int
+do_event(int irq, struct trapframe *regs)
+{
+ struct cpu_info *ci;
+
+ if (irq >= NR_IRQS) {
+#ifdef DIAGNOSTIC
+ printf("event irq number %d > NR_IRQS\n", irq);
+#endif
+ return ENOENT;
+ }
+
+ if (0 && irq == 4) {
+ ci = &cpu_info_primary;
+ printf("do_event %d/%d called, ilevel %d\n", irq,
+ irq_to_evtchn[irq], ci->ci_ilevel);
+ }
+
+ ci = &cpu_info_primary;
+
+ hypervisor_acknowledge_irq(irq);
+ if (ci->ci_isources[irq] == NULL) {
+ return 0;
+ }
+ __asm__ __volatile__ (
+ " movl $1f,%%esi ;"
+ " jmp *%%eax ;"
+ "1: "
+ : : "a" (ci->ci_isources[irq]->is_recurse),
+ "b" (ci->ci_ilevel)
+ : "esi", "ecx", "edx", "memory");
+
+ if (0 && irq == 4)
+ printf("do_event %d done, ipending %08x\n", irq,
+ ci->ci_ipending);
+
+ return 0;
+}
+
+static int
+find_unbound_irq(void)
+{
+ int irq;
+
+ for (irq = 0; irq < NR_IRQS; irq++)
+ if (irq_bindcount[irq] == 0)
+ break;
+
+ if (irq == NR_IRQS)
+ panic("No available IRQ to bind to: increase NR_IRQS!\n");
+
+ return irq;
+}
+
+int
+bind_virq_to_irq(int virq)
+{
+ evtchn_op_t op;
+ int evtchn, irq;
+
+ simple_lock(&irq_mapping_update_lock);
+
+ irq = virq_to_irq[virq];
+ if (irq == -1) {
+ op.cmd = EVTCHNOP_bind_virq;
+ op.u.bind_virq.virq = virq;
+ if (HYPERVISOR_event_channel_op(&op) != 0)
+ panic("Failed to bind virtual IRQ %d\n", virq);
+ evtchn = op.u.bind_virq.port;
+
+ irq = find_unbound_irq();
+ evtchn_to_irq[evtchn] = irq;
+ irq_to_evtchn[irq] = evtchn;
+
+ virq_to_irq[virq] = irq;
+ }
+
+ irq_bindcount[irq]++;
+
+ simple_unlock(&irq_mapping_update_lock);
+
+ return irq;
+}
+
+void
+unbind_virq_from_irq(int virq)
+{
+ evtchn_op_t op;
+ int irq = virq_to_irq[virq];
+ int evtchn = irq_to_evtchn[irq];
+
+ simple_lock(&irq_mapping_update_lock);
+
+ irq_bindcount[irq]--;
+ if (irq_bindcount[irq] == 0) {
+ op.cmd = EVTCHNOP_close;
+ op.u.close.dom = DOMID_SELF;
+ op.u.close.port = evtchn;
+ if (HYPERVISOR_event_channel_op(&op) != 0)
+ panic("Failed to unbind virtual IRQ %d\n", virq);
+
+ evtchn_to_irq[evtchn] = -1;
+ irq_to_evtchn[irq] = -1;
+ virq_to_irq[virq] = -1;
+ }
+
+ simple_unlock(&irq_mapping_update_lock);
+}
+
+int bind_evtchn_to_irq(int evtchn)
+{
+ int irq;
+
+ simple_lock(&irq_mapping_update_lock);
+
+ irq = evtchn_to_irq[evtchn];
+ if (irq == -1) {
+ irq = find_unbound_irq();
+ evtchn_to_irq[evtchn] = irq;
+ irq_to_evtchn[irq] = evtchn;
+ }
+
+ irq_bindcount[irq]++;
+
+ simple_unlock(&irq_mapping_update_lock);
+
+ return irq;
+}
+
+int
+event_set_handler(int irq, ev_handler_t handler, void *arg, int level)
+{
+ struct intrsource *isp;
+ struct intrhand *ih;
+ struct cpu_info *ci;
+
+ if (irq >= NR_IRQS) {
+#ifdef DIAGNOSTIC
+ printf("irq number %d > NR_IRQS\n", irq);
+#endif
+ return ENOENT;
+ }
+
+#if 0
+ printf("event_set_handler irq %d/%d handler %p level %d\n", irq,
+ irq_to_evtchn[irq], handler, level);
+#endif
+ /* XXXcl handle already bound irq */
+
+ MALLOC(isp, struct intrsource *, sizeof (struct intrsource), M_DEVBUF,
+ M_WAITOK|M_ZERO);
+ if (isp == NULL)
+ panic("can't allocate fixed interrupt source");
+ MALLOC(ih, struct intrhand *, sizeof (struct intrhand), M_DEVBUF,
+ M_WAITOK|M_ZERO);
+ if (ih == NULL)
+ panic("can't allocate fixed interrupt source");
+
+ ci = &cpu_info_primary;
+
+ isp->is_recurse = xenev_stubs[irq].ist_recurse;
+ isp->is_resume = xenev_stubs[irq].ist_resume;
+ ih->ih_level = level;
+ ih->ih_fun = handler;
+ ih->ih_arg = arg;
+ ih->ih_next = NULL;
+ isp->is_handlers = ih;
+ isp->is_pic = &xenev_pic;
+ ci->ci_isources[irq] = isp;
+ evcnt_attach_dynamic(&isp->is_evcnt, EVCNT_TYPE_INTR, NULL,
+ ci->ci_dev->dv_xname, "xenev");
+
+ intr_calculatemasks(ci);
+
+ return 0;
+}
+
+void hypervisor_enable_irq(unsigned int irq)
+{
+
+ hypervisor_unmask_event(irq_to_evtchn[irq]);
+}
+
+void hypervisor_disable_irq(unsigned int irq)
+{
+
+ hypervisor_mask_event(irq_to_evtchn[irq]);
+}
+
+void hypervisor_acknowledge_irq(unsigned int irq)
+{
+
+ hypervisor_mask_event(irq_to_evtchn[irq]);
+ hypervisor_clear_event(irq_to_evtchn[irq]);
+}
+
+#if 0
+static int
+xen_die_handler(void *arg)
+{
+ printf("hypervisor: DIE event received...\n");
+ cpu_reboot(0, NULL);
+ /* NOTREACHED */
+ return 0;
+}
+#endif
+
+static int
+xen_debug_handler(void *arg)
+{
+ printf("debug event\n");
+ return 0;
+}
+
+static int
+xen_misdirect_handler(void *arg)
+{
+#if 0
+ char *msg = "misdirect\n";
+ (void)HYPERVISOR_console_io(CONSOLEIO_write, strlen(msg), msg);
+#endif
+ return 0;
+}