diff options
-rw-r--r-- | device/ds_routines.c | 5 | ||||
-rw-r--r-- | device/interrupt.h | 8 | ||||
-rw-r--r-- | device/intr.c | 63 | ||||
-rw-r--r-- | include/device/intr.h | 4 | ||||
-rw-r--r-- | ipc/ipc_port.c | 4 | ||||
-rw-r--r-- | linux/dev/arch/i386/kernel/irq.c | 50 |
6 files changed, 87 insertions, 47 deletions
diff --git a/device/ds_routines.c b/device/ds_routines.c index 74569aa..a54bb0e 100644 --- a/device/ds_routines.c +++ b/device/ds_routines.c @@ -333,7 +333,7 @@ experimental_device_intr_register (ipc_port_t master_port, int line, if (master_port != master_device_port) return D_INVALID_OPERATION; - if (receive_port == MACH_PORT_NULL) + if (receive_port == IP_NULL) return D_INVALID_OPERATION; /* XXX: move to arch-specific */ @@ -362,7 +362,7 @@ experimental_device_intr_register2 (ipc_port_t master_port, int line, if (master_port != master_device_port) return D_INVALID_OPERATION; - if (notification_port == MACH_PORT_NULL) + if (notification_port == IP_NULL) return D_INVALID_OPERATION; /* XXX: move to arch-specific */ @@ -1860,6 +1860,7 @@ device_writev_trap (mach_device_t device, dev_mode_t mode, kern_return_t experimental_device_intr_enable(ipc_port_t master_port, int line, char status) { + return D_INVALID_OPERATION; #ifdef MACH_XEN return D_INVALID_OPERATION; #else /* MACH_XEN */ diff --git a/device/interrupt.h b/device/interrupt.h index 12e6efc..7a00456 100644 --- a/device/interrupt.h +++ b/device/interrupt.h @@ -24,11 +24,13 @@ kern_return_t insert_intr_entry (int line, ipc_port_t dest, int new_style, /* version2 notifications? */ struct intr_entry **entry); +boolean_t intr_entry_notify (mach_msg_header_t *msg); +void intr_thread (void); + +/* linux/dev/arch/i386/kernel/irq.c */ int install_user_intr_handler (unsigned int line, unsigned long flags, struct intr_entry *entry); - -boolean_t intr_entry_notify (mach_msg_header_t *msg); -void intr_thread (void); +int remove_user_intr_handler (unsigned int irq, struct intr_entry *entry); #endif /* DEVICE_INTERRUPT_H */ diff --git a/device/intr.c b/device/intr.c index 143bed3..5033d93 100644 --- a/device/intr.c +++ b/device/intr.c @@ -172,9 +172,23 @@ intr_entry_port_lookup (ipc_port_t port) boolean_t intr_entry_notify (mach_msg_header_t *msg) { - if (msg->msgh_id == MACH_NOTIFY_DEAD_NAME) + struct intr_entry *entry; + + if (msg->msgh_id == MACH_NOTIFY_NO_SENDERS) + { + extern void enable_irq (unsigned int irq_nr); + mach_no_senders_notification_t *ns; + + ns = (mach_no_senders_notification_t *) msg; + entry = intr_entry_port_lookup + ((ipc_port_t) ns->not_header.msgh_remote_port); + assert (entry); + + enable_irq (entry->line); /* entry is not locked here */ + return TRUE; + } + else if (msg->msgh_id == MACH_NOTIFY_DEAD_NAME) { - struct intr_entry *entry; int line; mach_dead_name_notification_t *dn; unsigned long flags; @@ -188,6 +202,7 @@ intr_entry_notify (mach_msg_header_t *msg) line = entry->line; assert (!queue_empty (&intr_queue)); queue_remove (&intr_queue, entry, struct intr_entry *, chain); + remove_user_intr_handler (entry->line, entry); cpu_intr_restore (flags); ipc_port_dealloc_kernel (entry->port); @@ -212,7 +227,8 @@ init_mach_intr_notification (mach_intr_notification_t *n) mach_msg_header_t *m = &n->intr_header; mach_msg_type_t *t = &n->intr_type; - m->msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND, 0); + m->msgh_bits = MACH_MSGH_BITS (MACH_MSG_TYPE_PORT_SEND, + MACH_MSG_TYPE_PORT_SEND); m->msgh_size = sizeof *n; m->msgh_seqno = INTR_NOTIFY_MSGH_SEQNO; m->msgh_local_port = MACH_PORT_NULL; @@ -229,10 +245,11 @@ init_mach_intr_notification (mach_intr_notification_t *n) } static boolean_t -deliver_intr (int line, ipc_port_t dest_port) +deliver_intr (int line, ipc_port_t dest_port, ipc_port_t interrupt_port) { ipc_kmsg_t kmsg; mach_intr_notification_t *n; + ipc_port_t sright, sonce, old; mach_port_t dest = (mach_port_t) dest_port; if (dest == MACH_PORT_NULL) @@ -246,7 +263,17 @@ deliver_intr (int line, ipc_port_t dest_port) n = (mach_intr_notification_t *) &kmsg->ikm_header; *n = mach_intr_notification_template; + /* Arrange no-senders notification. */ + sright = ipc_port_make_send (interrupt_port); + sonce = ipc_port_make_sonce (interrupt_port); + ip_lock (interrupt_port); + ipc_port_nsrequest (interrupt_port, interrupt_port->ip_mscount, + sonce, &old); + if (old != IP_NULL) + ipc_port_release_sonce (old); + n->intr_header.msgh_remote_port = dest; + n->intr_header.msgh_local_port = (mach_port_t) sright; n->line = line; ipc_port_copy_send (dest_port); @@ -269,7 +296,7 @@ init_mach_intr_notification2 (mach_intr_notification2_t *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; + m->msgh_id = MACH_INTR_NOTIFY2; t->msgt_name = MACH_MSG_TYPE_INTEGER_32; t->msgt_size = 32; @@ -289,7 +316,7 @@ init_mach_intr_notification2 (mach_intr_notification2_t *n) t->msgt_unused = 0; t = &n->port_type; - t->msgt_name = MACH_MSG_TYPE_MAKE_SEND; + t->msgt_name = MACH_MSG_TYPE_MOVE_SEND; t->msgt_size = 32; t->msgt_number = 1; t->msgt_inline = TRUE; @@ -304,6 +331,7 @@ deliver_intr_notification2 (ipc_port_t notification_port, ipc_port_t interrupt_port) { ipc_kmsg_t kmsg; + ipc_port_t sright, sonce, old; mach_intr_notification2_t *n; assert (notification_port); @@ -317,10 +345,19 @@ deliver_intr_notification2 (ipc_port_t notification_port, n = (mach_intr_notification2_t *) &kmsg->ikm_header; *n = mach_intr_notification2_template; + /* Arrange no-senders notification. */ + sright = ipc_port_make_send (interrupt_port); + sonce = ipc_port_make_sonce (interrupt_port); + ip_lock (interrupt_port); + ipc_port_nsrequest (interrupt_port, interrupt_port->ip_mscount, + sonce, &old); + if (old != IP_NULL) + ipc_port_release_sonce (old); + 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; + n->interrupt_port = (mach_port_t) sright; ipc_port_copy_send (notification_port); ipc_mqueue_send_always(kmsg); @@ -351,16 +388,18 @@ intr_thread () queue_iterate (&intr_queue, e, struct intr_entry *, chain) if (e->interrupts) { + int ok; + ipc_port_t interrupt_port = e->port; + int count = e->interrupts; line = e->line; dest = e->dest; 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); + ok = deliver_intr_notification2 (dest, line, count, interrupt_port); + printf ("new: count? %d ok? %d\n", count, ok); cpu_intr_save (&flags); } else @@ -368,8 +407,10 @@ intr_thread () e->interrupts--; cpu_intr_restore (flags); - deliver_intr (line, dest); + deliver_intr (line, dest, interrupt_port); cpu_intr_save (&flags); + + assert (e->interrupts == 0); } /* We cannot assume that e still exists at this point diff --git a/include/device/intr.h b/include/device/intr.h index e7aa7e2..c1aa638 100644 --- a/include/device/intr.h +++ b/include/device/intr.h @@ -16,8 +16,12 @@ typedef struct mach_msg_header_t intr_header; mach_msg_type_t line_type; mach_msg_type_number_t line; + /* double check that count can be > 1 */ + /* it can not */ mach_msg_type_t count_type; mach_msg_type_number_t count; + /* actually, we might be able to stuff this port into the response port */ + /* works nicely */ mach_msg_type_t port_type; mach_port_t interrupt_port; } mach_intr_notification2_t; diff --git a/ipc/ipc_port.c b/ipc/ipc_port.c index 86a4ee2..a608e6e 100644 --- a/ipc/ipc_port.c +++ b/ipc/ipc_port.c @@ -310,6 +310,7 @@ ipc_port_nsrequest( { ipc_port_t previous; mach_port_mscount_t mscount; + mach_port_mscount_t mscount_max = (mach_port_mscount_t) ~0; assert(ip_active(port)); @@ -317,7 +318,8 @@ ipc_port_nsrequest( mscount = port->ip_mscount; if ((port->ip_srights == 0) && - (sync <= mscount) && + (sync <= mscount + || (sync == mscount_max && mscount < mscount_max)) && (notify != IP_NULL)) { port->ip_nsrequest = IP_NULL; ip_unlock(port); diff --git a/linux/dev/arch/i386/kernel/irq.c b/linux/dev/arch/i386/kernel/irq.c index 15f95c3..e2c18c7 100644 --- a/linux/dev/arch/i386/kernel/irq.c +++ b/linux/dev/arch/i386/kernel/irq.c @@ -104,7 +104,6 @@ linux_intr (int irq) { struct pt_regs regs; struct linux_action *action = *(irq_action + irq); - struct linux_action **prev = &irq_action[irq]; unsigned long flags; kstat.interrupts[irq]++; @@ -123,18 +122,10 @@ linux_intr (int irq) /* We disable the irq here and it will be enabled * after the interrupt is handled by the user space driver. */ disable_irq (irq); - if (! queue_intr (action->userspace_handler)) - { - *prev = action->next; - linux_kfree(action); - action = *prev; - enable_irq (irq); - continue; - } + queue_intr (action->userspace_handler); } else if (action->handler) action->handler (irq, action->dev_id, ®s); - prev = &action->next; action = action->next; } @@ -277,30 +268,10 @@ install_user_intr_handler (unsigned int irq, unsigned long flags, struct intr_entry *entry) { struct linux_action *action; -#if 0 - struct linux_action *old; -#endif int retval; assert (irq < 16); -#if 0 - /* Test whether the irq handler has already been set. */ - /* JW: Actually, that cannot happen. We test for that in - device_intr_register before calling this function. */ - // TODO I need to protect the array when iterating it. - old = irq_action[irq]; - while (old) - { - if (old->delivery_port == entry->dest) - { - printk ("The interrupt handler has been installed on line %d", irq); - return linux_to_mach_error (-EAGAIN); - } - old = old->next; - } -#endif - /* * Hmm... Should I use `kalloc()' ? * By OKUJI Yoshinori. @@ -323,6 +294,25 @@ install_user_intr_handler (unsigned int irq, unsigned long flags, return linux_to_mach_error (retval); } +int +remove_user_intr_handler (unsigned int irq, struct intr_entry *entry) +{ + struct linux_action *action, **prev; + + for (prev = &irq_action[irq], action = irq_action[irq]; + action; + prev = &action->next, action = action->next) + if (action->userspace_handler == entry) + { + *prev = action->next; + linux_kfree(action); + enable_irq (irq); + return 1; + } + + return 0; +} + /* * Attach a handler to an IRQ. */ |