diff options
Diffstat (limited to 'device')
-rw-r--r-- | device/ds_routines.c | 23 | ||||
-rw-r--r-- | device/ds_routines.h | 3 | ||||
-rw-r--r-- | device/interrupt.h | 3 | ||||
-rw-r--r-- | device/intr.c | 74 |
4 files changed, 41 insertions, 62 deletions
diff --git a/device/ds_routines.c b/device/ds_routines.c index d866acc..ec26044 100644 --- a/device/ds_routines.c +++ b/device/ds_routines.c @@ -326,7 +326,6 @@ experimental_device_intr_register (ipc_port_t master_port, int line, #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. */ @@ -336,15 +335,7 @@ experimental_device_intr_register (ipc_port_t master_port, int line, if (receive_port == IP_NULL) return D_INVALID_OPERATION; - /* XXX: move to arch-specific */ - if (line < 0 || line >= 16) - return D_INVALID_OPERATION; - - ret = insert_intr_entry (line, receive_port, &entry); - if (ret) - return ret; - - return install_user_intr_handler (line, flags, entry); + return insert_intr_entry (line, receive_port); #endif /* MACH_XEN */ } @@ -1832,18 +1823,6 @@ 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 */ - if (master_port != master_device_port) - return D_INVALID_OPERATION; - - if (! status) - return D_INVALID_OPERATION; - - enable_irq (line); - return 0; -#endif /* MACH_XEN */ } struct device_emulation_ops mach_device_emulation_ops = diff --git a/device/ds_routines.h b/device/ds_routines.h index e9f115f..c0543cb 100644 --- a/device/ds_routines.h +++ b/device/ds_routines.h @@ -83,7 +83,4 @@ io_return_t ds_device_writev_trap( io_buf_vec_t *iovec, vm_size_t count); -/* XXX arch-specific */ -extern ipc_port_t intr_rcv_ports[16]; - #endif /* DS_ROUTINES_H */ diff --git a/device/interrupt.h b/device/interrupt.h index 1987ffc..855f163 100644 --- a/device/interrupt.h +++ b/device/interrupt.h @@ -20,8 +20,7 @@ struct intr_entry; boolean_t queue_intr (struct intr_entry *e); -kern_return_t insert_intr_entry (int line, ipc_port_t dest, - struct intr_entry **entry); +kern_return_t insert_intr_entry (int line, ipc_port_t notification_port); boolean_t intr_entry_notify (mach_msg_header_t *msg); void intr_thread (void); diff --git a/device/intr.c b/device/intr.c index 20a888c..85915cd 100644 --- a/device/intr.c +++ b/device/intr.c @@ -35,7 +35,7 @@ struct intr_entry { ipc_port_t port; /* We receive notifications on this port. */ queue_chain_t chain; - ipc_port_t dest; + ipc_port_t notification_port; int line; /* The number of interrupts occur since last run of intr_thread. */ int interrupts; @@ -62,9 +62,7 @@ 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 notification_port) { kern_return_t err = 0; unsigned long flags; @@ -73,6 +71,10 @@ insert_intr_entry (int line, ipc_port_t dnnotify; ipc_port_request_index_t dnindex; + /* XXX: move to arch-specific */ + if (line < 0 || line >= 16) + return D_INVALID_OPERATION; + new = (struct intr_entry *) kmem_cache_alloc (&intr_entry_cache); if (new == NULL) return D_NO_MEMORY; @@ -89,41 +91,41 @@ insert_intr_entry (int line, ipc_kobject_set (new->port, (ipc_kobject_t) new, IKOT_INTR_ENTRY); new->line = line; - new->dest = dest; + new->notification_port = notification_port; new->interrupts = 0; /* Register a dead-name notification so that we are notified if the userspace handler dies. */ dnnotify = ipc_port_make_sonce (new->port); - ip_lock (dest); + ip_lock (notification_port); /* We use a bogus port name. We don't need it to distinguish the notifications because we register just one per object. */ retry: - err = ipc_port_dnrequest (dest, (mach_port_t) 1, dnnotify, &dnindex); + err = ipc_port_dnrequest (notification_port, (mach_port_t) 1, dnnotify, &dnindex); if (err) { - err = ipc_port_dngrow (dest); - /* dest is unlocked */ + err = ipc_port_dngrow (notification_port); + /* notification_port is unlocked */ if (err != KERN_SUCCESS) { ipc_port_release_sonce (dnnotify); kmem_cache_free (&intr_entry_cache, (vm_offset_t) new); return err; } - ip_lock (dest); + ip_lock (notification_port); goto retry; } - /* dest is locked. dnindex is only valid until we unlock it and we + /* notification_port is locked. dnindex is only valid until we unlock it and we might decide to cancel. */ /* check whether the intr entry has been in the queue. */ cpu_intr_save (&flags); queue_iterate (&intr_queue, e, struct intr_entry *, chain) - if (e->dest == dest && e->line == line) + if (e->notification_port == notification_port && e->line == line) { printf ("the interrupt entry for line %d and port %p " "has already been inserted before.\n", - line, dest); + line, notification_port); free = 1; err = D_ALREADY_OPEN; goto out; @@ -133,16 +135,19 @@ insert_intr_entry (int line, cpu_intr_restore (flags); if (free) { - ipc_port_dncancel (new->dest, (mach_port_t) 1, dnindex); - ip_unlock (new->dest); + ipc_port_dncancel (new->notification_port, (mach_port_t) 1, dnindex); + ip_unlock (new->notification_port); ipc_port_release_sonce (dnnotify); ipc_port_dealloc_kernel (new->port); - ipc_port_release_send (new->dest); + ipc_port_release_send (new->notification_port); kmem_cache_free (&intr_entry_cache, (vm_offset_t) new); } else - ip_unlock (new->dest); - *entry = new; + ip_unlock (new->notification_port); + + if (! err) + err = install_user_intr_handler (line, flags, new); + return err; } @@ -173,6 +178,7 @@ intr_entry_notify (mach_msg_header_t *msg) if (msg->msgh_id == MACH_NOTIFY_NO_SENDERS) { + /* XXX uses internal Linux IRQ handling function. */ extern void enable_irq (unsigned int irq_nr); mach_no_senders_notification_t *ns; @@ -181,7 +187,7 @@ intr_entry_notify (mach_msg_header_t *msg) ((ipc_port_t) ns->not_header.msgh_remote_port); assert (entry); - enable_irq (entry->line); /* entry is not locked here */ + enable_irq (entry->line); return TRUE; } else if (msg->msgh_id == MACH_NOTIFY_DEAD_NAME) @@ -203,10 +209,9 @@ intr_entry_notify (mach_msg_header_t *msg) cpu_intr_restore (flags); ipc_port_dealloc_kernel (entry->port); - ipc_port_release_send (entry->dest); + ipc_port_release_send (entry->notification_port); kmem_cache_free (&intr_entry_cache, (vm_offset_t) entry); - /* XXX cancel no-senders notification here */ printf ("irq handler %d: userspace handler died\n", line); return TRUE; } @@ -243,14 +248,16 @@ init_mach_intr_notification (mach_intr_notification_t *n) } static boolean_t -deliver_intr (int line, ipc_port_t dest_port, ipc_port_t interrupt_port) +deliver_intr (int line, ipc_port_t notification_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) + if (notification_port == IP_NULL) + return FALSE; + + if (interrupt_port == IP_NULL) return FALSE; kmsg = ikm_alloc(sizeof *n); @@ -270,12 +277,12 @@ deliver_intr (int line, ipc_port_t dest_port, ipc_port_t interrupt_port) if (old != IP_NULL) ipc_port_release_sonce (old); - n->intr_header.msgh_remote_port = dest; + n->intr_header.msgh_remote_port = (mach_port_t) notification_port; n->intr_header.msgh_local_port = (mach_port_t) sright; n->line = line; - ipc_port_copy_send (dest_port); - ipc_mqueue_send_always(kmsg); + ipc_port_copy_send (notification_port); + ipc_mqueue_send_always (kmsg); return TRUE; } @@ -283,9 +290,6 @@ deliver_intr (int line, ipc_port_t dest_port, ipc_port_t interrupt_port) void intr_thread () { - struct intr_entry *e; - int line; - ipc_port_t dest; queue_init (&intr_queue); init_mach_intr_notification (&mach_intr_notification_template); @@ -294,6 +298,7 @@ intr_thread () for (;;) { + struct intr_entry *e; unsigned long flags; assert_wait ((event_t) &intr_thread, FALSE); cpu_intr_save (&flags); @@ -302,16 +307,15 @@ intr_thread () queue_iterate (&intr_queue, e, struct intr_entry *, chain) if (e->interrupts) { - int ok; + int line = e->line; + ipc_port_t notification_port = e->notification_port; ipc_port_t interrupt_port = e->port; - int count = e->interrupts; - line = e->line; - dest = e->dest; + assert (e->interrupts == 1); e->interrupts--; cpu_intr_restore (flags); - deliver_intr (line, dest, interrupt_port); + deliver_intr (line, notification_port, interrupt_port); cpu_intr_save (&flags); |