summaryrefslogtreecommitdiff
path: root/device
diff options
context:
space:
mode:
authorJustus Winter <justus@gnupg.org>2016-02-27 09:10:23 +0100
committerJustus Winter <justus@gnupg.org>2016-02-27 09:10:23 +0100
commit2cf0c62f09dc2069a9446a5a694bb73dd1322108 (patch)
tree0cb0d4b951f4ec9efa4686b2b3d9c05c92fed9eb /device
parent9482ee4ba48f8033f7916551f2767f48f9bd0c55 (diff)
No need for a new kind of notification, we can provide a smoother upgrade path
Diffstat (limited to 'device')
-rw-r--r--device/ds_routines.c5
-rw-r--r--device/interrupt.h8
-rw-r--r--device/intr.c63
3 files changed, 60 insertions, 16 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