diff options
-rw-r--r-- | device/ds_routines.c | 31 | ||||
-rw-r--r-- | device/interrupt.h | 1 | ||||
-rw-r--r-- | device/intr.c | 104 | ||||
-rw-r--r-- | include/device/intr.h | 12 | ||||
-rw-r--r-- | include/mach/experimental.defs | 14 |
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); */ |