summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--device/ds_routines.c5
-rw-r--r--device/interrupt.h8
-rw-r--r--device/intr.c63
-rw-r--r--include/device/intr.h4
-rw-r--r--ipc/ipc_port.c4
-rw-r--r--linux/dev/arch/i386/kernel/irq.c50
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, &regs);
- 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.
*/