summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--device/ds_routines.c31
-rw-r--r--device/interrupt.h1
-rw-r--r--device/intr.c104
-rw-r--r--include/device/intr.h12
-rw-r--r--include/mach/experimental.defs14
5 files changed, 155 insertions, 7 deletions
diff --git a/device/ds_routines.c b/device/ds_routines.c
index 2b9869a..74569aa 100644
--- a/device/ds_routines.c
+++ b/device/ds_routines.c
@@ -340,7 +340,36 @@ experimental_device_intr_register (ipc_port_t master_port, int line,
if (line < 0 || line >= 16)
return D_INVALID_OPERATION;
- ret = insert_intr_entry (line, receive_port, &entry);
+ ret = insert_intr_entry (line, receive_port, FALSE, &entry);
+ if (ret)
+ return ret;
+
+ return install_user_intr_handler (line, flags, entry);
+#endif /* MACH_XEN */
+}
+
+io_return_t
+experimental_device_intr_register2 (ipc_port_t master_port, int line,
+ int flags, ipc_port_t notification_port)
+{
+#ifdef MACH_XEN
+ return D_INVALID_OPERATION;
+#else /* MACH_XEN */
+ struct intr_entry *entry;
+ io_return_t ret;
+
+ /* Open must be called on the master device port. */
+ if (master_port != master_device_port)
+ return D_INVALID_OPERATION;
+
+ if (notification_port == MACH_PORT_NULL)
+ return D_INVALID_OPERATION;
+
+ /* XXX: move to arch-specific */
+ if (line < 0 || line >= 16)
+ return D_INVALID_OPERATION;
+
+ ret = insert_intr_entry (line, notification_port, TRUE, &entry);
if (ret)
return ret;
diff --git a/device/interrupt.h b/device/interrupt.h
index c43c3e0..12e6efc 100644
--- a/device/interrupt.h
+++ b/device/interrupt.h
@@ -21,6 +21,7 @@
struct intr_entry;
boolean_t queue_intr (struct intr_entry *e);
kern_return_t insert_intr_entry (int line, ipc_port_t dest,
+ int new_style, /* version2 notifications? */
struct intr_entry **entry);
int install_user_intr_handler (unsigned int line,
diff --git a/device/intr.c b/device/intr.c
index c930e84..143bed3 100644
--- a/device/intr.c
+++ b/device/intr.c
@@ -36,6 +36,7 @@ struct intr_entry
ipc_port_t port; /* We receive notifications on this port. */
queue_chain_t chain;
ipc_port_t dest;
+ int new_style; /* version2 notifications?. */
int line;
/* The number of interrupts occur since last run of intr_thread. */
int interrupts;
@@ -62,7 +63,10 @@ queue_intr (struct intr_entry *e)
* This entry exists in the queue until
* the corresponding interrupt port is removed.*/
kern_return_t
-insert_intr_entry (int line, ipc_port_t dest, struct intr_entry **entry)
+insert_intr_entry (int line,
+ ipc_port_t dest,
+ int new_style, /* version2 notifications? */
+ struct intr_entry **entry)
{
kern_return_t err = 0;
unsigned long flags;
@@ -88,6 +92,7 @@ insert_intr_entry (int line, ipc_port_t dest, struct intr_entry **entry)
new->line = line;
new->dest = dest;
+ new->new_style = new_style;
new->interrupts = 0;
/* Register a dead-name notification so that we are notified if the
@@ -250,6 +255,79 @@ deliver_intr (int line, ipc_port_t dest_port)
return TRUE;
}
+mach_intr_notification2_t mach_intr_notification2_template;
+
+static void
+init_mach_intr_notification2 (mach_intr_notification2_t *n)
+{
+ mach_msg_header_t *m = &n->intr_header;
+ mach_msg_type_t *t = &n->line_type;
+
+ m->msgh_bits =
+ MACH_MSGH_BITS_COMPLEX | MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND, 0);
+ m->msgh_size = sizeof *n;
+ m->msgh_seqno = INTR_NOTIFY_MSGH_SEQNO;
+ m->msgh_local_port = MACH_PORT_NULL;
+ m->msgh_remote_port = MACH_PORT_NULL;
+ m->msgh_id = MACH_INTR_NOTIFY;
+
+ t->msgt_name = MACH_MSG_TYPE_INTEGER_32;
+ t->msgt_size = 32;
+ t->msgt_number = 1;
+ t->msgt_inline = TRUE;
+ t->msgt_longform = FALSE;
+ t->msgt_deallocate = FALSE;
+ t->msgt_unused = 0;
+
+ t = &n->count_type;
+ t->msgt_name = MACH_MSG_TYPE_INTEGER_32;
+ t->msgt_size = 32;
+ t->msgt_number = 1;
+ t->msgt_inline = TRUE;
+ t->msgt_longform = FALSE;
+ t->msgt_deallocate = FALSE;
+ t->msgt_unused = 0;
+
+ t = &n->port_type;
+ t->msgt_name = MACH_MSG_TYPE_MAKE_SEND;
+ t->msgt_size = 32;
+ t->msgt_number = 1;
+ t->msgt_inline = TRUE;
+ t->msgt_longform = FALSE;
+ t->msgt_deallocate = FALSE;
+ t->msgt_unused = 0;
+}
+
+static boolean_t
+deliver_intr_notification2 (ipc_port_t notification_port,
+ int line, int count,
+ ipc_port_t interrupt_port)
+{
+ ipc_kmsg_t kmsg;
+ mach_intr_notification2_t *n;
+
+ assert (notification_port);
+ assert (interrupt_port);
+
+ kmsg = ikm_alloc(sizeof *n);
+ if (kmsg == IKM_NULL)
+ return FALSE;
+
+ ikm_init(kmsg, sizeof *n);
+ n = (mach_intr_notification2_t *) &kmsg->ikm_header;
+ *n = mach_intr_notification2_template;
+
+ n->intr_header.msgh_remote_port = (mach_port_t) notification_port;
+ n->line = line;
+ n->count = count;
+ n->interrupt_port = (mach_port_t) interrupt_port;
+
+ ipc_port_copy_send (notification_port);
+ ipc_mqueue_send_always(kmsg);
+
+ return TRUE;
+}
+
void
intr_thread ()
{
@@ -258,6 +336,7 @@ intr_thread ()
ipc_port_t dest;
queue_init (&intr_queue);
init_mach_intr_notification (&mach_intr_notification_template);
+ init_mach_intr_notification2 (&mach_intr_notification2_template);
kmem_cache_init (&intr_entry_cache, "intr_entry",
sizeof (struct intr_entry), 0, NULL, 0);
@@ -274,11 +353,24 @@ intr_thread ()
{
line = e->line;
dest = e->dest;
- e->interrupts--;
-
- cpu_intr_restore (flags);
- deliver_intr (line, dest);
- cpu_intr_save (&flags);
+ if (e->new_style)
+ {
+ ipc_port_t interrupt_port = e->port;
+ int count = e->interrupts;
+ e->interrupts = 0;
+
+ cpu_intr_restore (flags);
+ deliver_intr_notification2 (dest, line, count, interrupt_port);
+ cpu_intr_save (&flags);
+ }
+ else
+ {
+ e->interrupts--;
+
+ cpu_intr_restore (flags);
+ deliver_intr (line, dest);
+ cpu_intr_save (&flags);
+ }
/* We cannot assume that e still exists at this point
because we released the lock. Hence we restart the
diff --git a/include/device/intr.h b/include/device/intr.h
index a02b64c..e7aa7e2 100644
--- a/include/device/intr.h
+++ b/include/device/intr.h
@@ -11,7 +11,19 @@ typedef struct
int line;
} mach_intr_notification_t;
+typedef struct
+{
+ mach_msg_header_t intr_header;
+ mach_msg_type_t line_type;
+ mach_msg_type_number_t line;
+ mach_msg_type_t count_type;
+ mach_msg_type_number_t count;
+ mach_msg_type_t port_type;
+ mach_port_t interrupt_port;
+} mach_intr_notification2_t;
+
#define INTR_NOTIFY_MSGH_SEQNO 0
#define MACH_INTR_NOTIFY 424242
+#define MACH_INTR_NOTIFY2 424247
#endif
diff --git a/include/mach/experimental.defs b/include/mach/experimental.defs
index 11c51d6..03fdee4 100644
--- a/include/mach/experimental.defs
+++ b/include/mach/experimental.defs
@@ -106,3 +106,17 @@ routine vm_allocate_contiguous(
out vaddr : vm_address_t;
out paddr : vm_address_t;
size : vm_size_t);
+
+/* 424246 */
+routine device_intr_register2(
+ master_port : mach_port_t;
+ line : int;
+ flags : int;
+ notification_port: mach_port_send_t);
+
+/* 424247 */
+skip; /* simpleroutine mach_intr_notify2(
+ notify : notify_port_t;
+ line : int,
+ count : int,
+ port : mach_port_send_t); */