diff options
author | Damien Zammit <damien@zamaudio.com> | 2020-07-09 23:11:44 +0200 |
---|---|---|
committer | Samuel Thibault <samuel.thibault@ens-lyon.org> | 2020-07-09 23:28:39 +0200 |
commit | c0240fcf66e7dc74bcebedfa75bb685fbff705cc (patch) | |
tree | dd701d76dd8bbc83ecaa929a602bf710dac8c855 /device | |
parent | 6cd23e1aa4f3557260e0cf75a2de2c142f8d8f48 (diff) |
Fix RPC interface
Diffstat (limited to 'device')
-rw-r--r-- | device/dev_hdr.h | 9 | ||||
-rw-r--r-- | device/ds_routines.c | 70 | ||||
-rw-r--r-- | device/ds_routines.h | 3 | ||||
-rw-r--r-- | device/intr.c | 183 | ||||
-rw-r--r-- | device/intr.h | 52 |
5 files changed, 153 insertions, 164 deletions
diff --git a/device/dev_hdr.h b/device/dev_hdr.h index ad98e0bb..4bd12c1c 100644 --- a/device/dev_hdr.h +++ b/device/dev_hdr.h @@ -146,4 +146,13 @@ extern void dev_set_indirection( dev_ops_t ops, int unit); +/* + * compare device name + */ +extern boolean_t __attribute__ ((pure)) +name_equal( + const char *src, + int len, + const char *target); + #endif /* _DEVICE_DEV_HDR_H_ */ diff --git a/device/ds_routines.c b/device/ds_routines.c index 1cc38f98..dd2978ed 100644 --- a/device/ds_routines.c +++ b/device/ds_routines.c @@ -322,44 +322,39 @@ ds_device_map (device_t dev, vm_prot_t prot, vm_offset_t offset, /* TODO: missing deregister support */ io_return_t -ds_device_intr_register (ipc_port_t master_port, int line, - int id, int flags, ipc_port_t receive_port) +ds_device_intr_register (device_t dev, int id, + int flags, ipc_port_t receive_port) { -#ifdef MACH_XEN - return D_INVALID_OPERATION; -#else /* MACH_XEN */ - io_return_t ret; + kern_return_t err; + mach_device_t mdev = dev->emul_data; - /* Open must be called on the master device port. */ - if (master_port != master_device_port) - return D_INVALID_OPERATION; + /* Refuse if device is dead or not completely open. */ + if (dev == DEVICE_NULL) + return D_NO_SUCH_DEVICE; + + /* No flag is defined for now */ + if (flags != 0) + return D_NO_SUCH_DEVICE; - /* XXX: move to arch-specific */ - if (line < 0 || line >= 16) + /* Must be called on the irq device only */ + if (! name_equal(mdev->dev_ops->d_name, 3, "irq")) return D_INVALID_OPERATION; - user_intr_t *user_intr = insert_intr_entry (line, receive_port); - if (!user_intr) + user_intr_t *e = insert_intr_entry (&irqtab, id, receive_port); + if (!e) return D_NO_MEMORY; + // TODO The original port should be replaced // when the same device driver calls it again, // in order to handle the case that the device driver crashes and restarts. - ret = install_user_intr_handler (line, flags, user_intr); - - if (ret == 0) - { - /* If the port is installed successfully, increase its reference by 1. - * Thus, the port won't be destroyed after its task is terminated. */ - ip_reference (receive_port); - - /* For now netdde calls device_intr_enable once after registration. Assume - * it does so for now. When we move to IRQ acknowledgment convention we will - * change this. */ - __disable_irq (line); - } - - return ret; -#endif /* MACH_XEN */ + err = install_user_intr_handler (&irqtab, id, flags, e); + if (err == D_SUCCESS) + { + /* If the port is installed successfully, increase its reference by 1. + * Thus, the port won't be destroyed after its task is terminated. */ + ip_reference (receive_port); + } + return err; } boolean_t @@ -1843,16 +1838,19 @@ device_writev_trap (mach_device_t device, dev_mode_t mode, } kern_return_t -ds_device_intr_enable(ipc_port_t master_port, int line, char status) +ds_device_intr_ack (device_t dev, ipc_port_t receive_port) { -#ifdef MACH_XEN - return D_INVALID_OPERATION; -#else /* MACH_XEN */ - if (master_port != master_device_port) + mach_device_t mdev = dev->emul_data; + + /* Refuse if device is dead or not completely open. */ + if (dev == DEVICE_NULL) + return D_NO_SUCH_DEVICE; + + /* Must be called on the irq device only */ + if (! name_equal(mdev->dev_ops->d_name, 3, "irq")) return D_INVALID_OPERATION; - return user_intr_enable(line, status); -#endif /* MACH_XEN */ + return irq_acknowledge(receive_port); } struct device_emulation_ops mach_device_emulation_ops = diff --git a/device/ds_routines.h b/device/ds_routines.h index e9f115fc..c0543cbc 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/intr.c b/device/intr.c index bbbdc92d..56f0c32c 100644 --- a/device/intr.c +++ b/device/intr.c @@ -13,121 +13,98 @@ */ #include <device/intr.h> -#include <device/ds_routines.h> -#include <kern/queue.h> +#include <device/device_types.h> +#include <device/device_port.h> +#include <device/notify.h> #include <kern/printf.h> #include <machine/spl.h> +#include <machine/irq.h> +#include <ipc/ipc_space.h> #ifndef MACH_XEN -static boolean_t deliver_intr (int line, ipc_port_t dest_port); +queue_head_t main_intr_queue; +static boolean_t deliver_intr (int id, ipc_port_t dst_port); -static queue_head_t intr_queue; -/* The total number of unprocessed interrupts. */ -static int tot_num_intr; - -static struct intr_entry * -search_intr (int line, ipc_port_t dest) +static user_intr_t * +search_intr (struct irqdev *dev, ipc_port_t dst_port) { - struct intr_entry *e; - queue_iterate (&intr_queue, e, struct intr_entry *, chain) + user_intr_t *e; + queue_iterate (dev->intr_queue, e, user_intr_t *, chain) { - if (e->dest == dest && e->line == line) + if (e->dst_port == dst_port) return e; } return NULL; } -static struct intr_entry * -search_intr_line (int line) +kern_return_t +irq_acknowledge (ipc_port_t receive_port) { - struct intr_entry *e; - queue_iterate (&intr_queue, e, struct intr_entry *, chain) - { - if (e->line == line && - (e->dest != MACH_PORT_NULL - && e->dest->ip_references != 1 - && e->unacked_interrupts)) - return e; - } - return NULL; -} - -kern_return_t user_intr_enable (int line, char status) -{ - struct intr_entry *e; - kern_return_t ret = D_SUCCESS; + user_intr_t *e; + kern_return_t ret; spl_t s = splhigh (); - /* FIXME: Use search_intr instead once we get the delivery port from ds_device_intr_enable, and get rid of search_intr_line */ - e = search_intr_line (line); + e = search_intr (&irqtab, receive_port); if (!e) - printf("didn't find user intr for interrupt %d!?\n", line); - else if (status) - { - if (!e->unacked_interrupts) - ret = D_INVALID_OPERATION; - else - e->unacked_interrupts--; - } + printf("didn't find user intr for interrupt !?\n"); else - { - e->unacked_interrupts++; - if (!e->unacked_interrupts) { - ret = D_INVALID_OPERATION; - e->unacked_interrupts--; + if (!e->n_unacked) + ret = D_INVALID_OPERATION; + else + e->n_unacked--; } - } splx (s); if (ret) return ret; - if (status) - /* TODO: better name for generic-to-arch-specific call */ - __enable_irq (line); - else - __disable_irq (line); + if (irqtab.irqdev_ack) + (*(irqtab.irqdev_ack)) (&irqtab, e->id); + + __enable_irq (irqtab.irq[e->id]); + return D_SUCCESS; } /* This function can only be used in the interrupt handler. */ static void -queue_intr (int line, user_intr_t *e) +queue_intr (struct irqdev *dev, int id, user_intr_t *e) { /* Until userland has handled the IRQ in the driver, we have to keep it * disabled. Level-triggered interrupts would keep raising otherwise. */ - __disable_irq (line); + __disable_irq (dev->irq[id]); spl_t s = splhigh (); - e->unacked_interrupts++; + e->n_unacked++; e->interrupts++; - tot_num_intr++; + dev->tot_num_intr++; splx (s); thread_wakeup ((event_t) &intr_thread); } -int deliver_user_intr (int line, user_intr_t *intr) +int +deliver_user_intr (struct irqdev *dev, int id, user_intr_t *e) { /* The reference of the port was increased * when the port was installed. * If the reference is 1, it means the port should * have been destroyed and I destroy it now. */ - if (intr->dest - && intr->dest->ip_references == 1) + if (e->dst_port + && e->dst_port->ip_references == 1) { - printf ("irq handler %d: release a dead delivery port %p entry %p\n", line, intr->dest, intr); - ipc_port_release (intr->dest); - intr->dest = MACH_PORT_NULL; + printf ("irq handler [%d]: release a dead delivery port %p entry %p\n", id, e->dst_port, e); + ipc_port_release (e->dst_port); + e->dst_port = MACH_PORT_NULL; thread_wakeup ((event_t) &intr_thread); return 0; } else { - queue_intr (line, intr); + queue_intr (dev, id, e); return 1; } } @@ -136,37 +113,32 @@ int deliver_user_intr (int line, user_intr_t *intr) * This entry exists in the queue until * the corresponding interrupt port is removed.*/ user_intr_t * -insert_intr_entry (int line, ipc_port_t dest) +insert_intr_entry (struct irqdev *dev, int id, ipc_port_t dst_port) { - struct intr_entry *e, *new, *ret; + user_intr_t *e, *new, *ret; int free = 0; - new = (struct intr_entry *) kalloc (sizeof (*new)); + new = (user_intr_t *) kalloc (sizeof (*new)); if (new == NULL) return NULL; /* check whether the intr entry has been in the queue. */ spl_t s = splhigh (); - e = search_intr (line, dest); + e = search_intr (dev, dst_port); if (e) { - printf ("the interrupt entry for line %d and port %p has already been inserted\n", line, dest); + printf ("the interrupt entry for irq[%d] and port %p has already been inserted\n", id, dst_port); free = 1; ret = NULL; goto out; } - printf("irq handler %d: new delivery port %p entry %p\n", line, dest, new); + printf("irq handler [%d]: new delivery port %p entry %p\n", id, dst_port, new); ret = new; - new->line = line; - new->dest = dest; + new->id = id; + new->dst_port = dst_port; new->interrupts = 0; - /* For now netdde calls device_intr_enable once after registration. Assume - * it does so for now. When we move to IRQ acknowledgment convention we will - * change this. */ - new->unacked_interrupts = 1; - - queue_enter (&intr_queue, new, struct intr_entry *, chain); + queue_enter (dev->intr_queue, new, user_intr_t *, chain); out: splx (s); if (free) @@ -177,10 +149,10 @@ out: void intr_thread (void) { - struct intr_entry *e; - int line; - ipc_port_t dest; - queue_init (&intr_queue); + user_intr_t *e; + int id; + ipc_port_t dst_port; + queue_init (&main_intr_queue); for (;;) { @@ -190,11 +162,11 @@ intr_thread (void) spl_t s = splhigh (); /* Check for aborted processes */ - queue_iterate (&intr_queue, e, struct intr_entry *, chain) + queue_iterate (&main_intr_queue, e, user_intr_t *, chain) { - if ((!e->dest || e->dest->ip_references == 1) && e->unacked_interrupts) + if ((!e->dst_port || e->dst_port->ip_references == 1) && e->n_unacked) { - printf ("irq handler %d: release dead delivery %d unacked irqs port %p entry %p\n", e->line, e->unacked_interrupts, e->dest, e); + printf ("irq handler [%d]: release dead delivery %d unacked irqs port %p entry %p\n", e->id, e->n_unacked, e->dst_port, e); /* The reference of the port was increased * when the port was installed. * If the reference is 1, it means the port should @@ -202,24 +174,24 @@ intr_thread (void) * handling can trigger, and we will cleanup later after the Linux * handler is cleared. */ /* TODO: rather immediately remove from Linux handler */ - while (e->unacked_interrupts) + while (e->n_unacked) { - __enable_irq(e->line); - e->unacked_interrupts--; + __enable_irq (irqtab.irq[e->id]); + e->n_unacked--; } } } /* Now check for interrupts */ - while (tot_num_intr) + while (irqtab.tot_num_intr) { int del = 0; - queue_iterate (&intr_queue, e, struct intr_entry *, chain) + queue_iterate (&main_intr_queue, e, user_intr_t *, chain) { /* if an entry doesn't have dest port, * we should remove it. */ - if (e->dest == MACH_PORT_NULL) + if (e->dst_port == MACH_PORT_NULL) { clear_wait (current_thread (), 0, 0); del = 1; @@ -229,13 +201,13 @@ intr_thread (void) if (e->interrupts) { clear_wait (current_thread (), 0, 0); - line = e->line; - dest = e->dest; + id = e->id; + dst_port = e->dst_port; e->interrupts--; - tot_num_intr--; + irqtab.tot_num_intr--; splx (s); - deliver_intr (line, dest); + deliver_intr (id, dst_port); s = splhigh (); } } @@ -243,16 +215,16 @@ intr_thread (void) /* remove the entry without dest port from the queue and free it. */ if (del) { - assert (!queue_empty (&intr_queue)); - queue_remove (&intr_queue, e, struct intr_entry *, chain); - if (e->unacked_interrupts) - printf("irq handler %d: still %d unacked irqs in entry %p\n", e->line, e->unacked_interrupts, e); - while (e->unacked_interrupts) + assert (!queue_empty (&main_intr_queue)); + queue_remove (&main_intr_queue, e, user_intr_t *, chain); + if (e->n_unacked) + printf("irq handler [%d]: still %d unacked irqs in entry %p\n", e->id, e->n_unacked, e); + while (e->n_unacked) { - __enable_irq(e->line); - e->unacked_interrupts--; + __enable_irq (irqtab.irq[e->id]); + e->n_unacked--; } - printf("irq handler %d: removed entry %p\n", e->line, e); + printf("irq handler [%d]: removed entry %p\n", e->id, e); splx (s); kfree ((vm_offset_t) e, sizeof (*e)); s = splhigh (); @@ -264,11 +236,11 @@ intr_thread (void) } static boolean_t -deliver_intr (int line, ipc_port_t dest_port) +deliver_intr (int id, ipc_port_t dst_port) { ipc_kmsg_t kmsg; device_intr_notification_t *n; - mach_port_t dest = (mach_port_t) dest_port; + mach_port_t dest = (mach_port_t) dst_port; if (dest == MACH_PORT_NULL) return FALSE; @@ -299,11 +271,12 @@ deliver_intr (int line, ipc_port_t dest_port) t->msgt_unused = 0; n->intr_header.msgh_remote_port = dest; - n->line = line; + n->id = id; - ipc_port_copy_send (dest_port); + ipc_port_copy_send (dst_port); ipc_mqueue_send_always(kmsg); return TRUE; } + #endif /* MACH_XEN */ diff --git a/device/intr.h b/device/intr.h index df282c05..cd3e0bce 100644 --- a/device/intr.h +++ b/device/intr.h @@ -15,36 +15,48 @@ #ifndef __INTR_H__ #define __INTR_H__ -#include <device/device_types.h> +#ifndef MACH_XEN + +#include <mach/kern_return.h> +#include <mach/port.h> #include <kern/queue.h> -#include <device/notify.h> +#include <ipc/ipc_port.h> +#include <device/conf.h> + +#define DEVICE_NOTIFY_MSGH_SEQNO 0 + +#include <sys/types.h> -typedef struct intr_entry -{ +struct irqdev; +#include <machine/irq.h> + +typedef struct { queue_chain_t chain; - ipc_port_t dest; - int line; - int interrupts; /* The number of interrupts occur since last run of intr_thread. */ - int unacked_interrupts; /* Number of times irqs were disabled for this */ + int interrupts; /* Number of interrupts occurred since last run of intr_thread */ + int n_unacked; /* Number of times irqs were disabled for this */ + ipc_port_t dst_port; /* Notification port */ + int id; /* Mapping to machine dependent irq_t array elem */ } user_intr_t; -#define DEVICE_NOTIFY_MSGH_SEQNO 0 - -int install_user_intr_handler (unsigned int line, - unsigned long flags, - user_intr_t *user_intr); +struct irqdev { + char *name; + void (*irqdev_ack)(struct irqdev *dev, int id); -/* Returns 0 if action should be removed */ -int deliver_user_intr (int line, user_intr_t *intr); + queue_head_t *intr_queue; + int tot_num_intr; /* Total number of unprocessed interrupts */ -user_intr_t *insert_intr_entry (int line, ipc_port_t dest); + /* Machine dependent */ + irq_t irq[NINTR]; +}; -/* TODO: should rather take delivery port */ -kern_return_t user_intr_enable (int line, char status); +extern queue_head_t main_intr_queue; +extern int install_user_intr_handler (struct irqdev *dev, int id, unsigned long flags, user_intr_t *e); +extern int deliver_user_intr (struct irqdev *dev, int id, user_intr_t *e); +extern user_intr_t *insert_intr_entry (struct irqdev *dev, int id, ipc_port_t receive_port); void intr_thread (void); +kern_return_t irq_acknowledge (ipc_port_t receive_port); -void __disable_irq(unsigned int); -void __enable_irq(unsigned int); +#endif /* MACH_XEN */ #endif |