>From c4cbaa810d34bd0dc62fbe0bad8961b7220c2a36 Mon Sep 17 00:00:00 2001 From: Damien Zammit Date: Sat, 27 Jun 2020 22:57:51 +1000 Subject: [PATCH] irq: Refactor interrupt handling as a mach device --- Makefrag.am | 4 +- device/dev_hdr.h | 9 + device/ds_routines.c | 77 ++++---- device/ds_routines.h | 3 - device/intr.h | 37 ---- device/{intr.c => irq.c} | 289 +++++++++++++++---------------- device/irq.h | 48 +++++ i386/Makefrag.am | 2 + i386/i386/irq.c | 30 ++++ i386/i386/irq.h | 13 ++ i386/i386/pic.c | 54 ++++++ i386/i386/pic.h | 2 + i386/i386at/conf.c | 8 + include/device/device.defs | 20 +-- include/device/notify.defs | 2 +- include/device/notify.h | 2 +- kern/startup.c | 2 +- linux/dev/arch/i386/kernel/irq.c | 53 +----- 18 files changed, 365 insertions(+), 290 deletions(-) delete mode 100644 device/intr.h rename device/{intr.c => irq.c} (51%) create mode 100644 device/irq.h create mode 100644 i386/i386/irq.c create mode 100644 i386/i386/irq.h diff --git a/Makefrag.am b/Makefrag.am index 73508350..d8147a40 100644 --- a/Makefrag.am +++ b/Makefrag.am @@ -313,8 +313,8 @@ libkernel_a_SOURCES += \ device/ds_routines.h \ device/if_ether.h \ device/if_hdr.h \ - device/intr.c \ - device/intr.h \ + device/irq.c \ + device/irq.h \ device/io_req.h \ device/net_io.c \ device/net_io.h \ 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 13c9a63e..2e231c54 100644 --- a/device/ds_routines.c +++ b/device/ds_routines.c @@ -92,9 +92,9 @@ #include #include #include -#include #include +#include #ifdef LINUX_DEV extern struct device_emulation_ops linux_block_emulation_ops; @@ -321,44 +321,40 @@ 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; - /* 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) - return D_NO_MEMORY; // TODO The original port should be replaced - // when the same device driver calls it again, + // 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 */ + user_intr_t *e = insert_intr_entry (&irqtab, id, receive_port); + if (!e) + return D_NO_MEMORY; + + 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); + + /* 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. */ + irq_disable (irqtab.irq[e->id]); + } + return err; } boolean_t @@ -1842,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_enable (device_t dev, int id) { -#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(id); } 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.h b/device/intr.h deleted file mode 100644 index 48843cf0..00000000 --- a/device/intr.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef __INTR_H__ - -#define __INTR_H__ - -#include -#include -#include - -typedef struct intr_entry -{ - 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 */ -} 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); - -/* Returns 0 if action should be removed */ -int deliver_user_intr (int line, user_intr_t *intr); - -user_intr_t *insert_intr_entry (int line, ipc_port_t dest); - -/* TODO: should rather take delivery port */ -kern_return_t user_intr_enable (int line, char status); - -void intr_thread (void); - -void __disable_irq(unsigned int); -void __enable_irq(unsigned int); - -#endif diff --git a/device/intr.c b/device/irq.c similarity index 51% rename from device/intr.c rename to device/irq.c index 1e9ab898..011f11df 100644 --- a/device/intr.c +++ b/device/irq.c @@ -1,119 +1,155 @@ -#include -#include -#include +#include +#include +#include +#include #include #include +#include +#include #ifndef MACH_XEN -static boolean_t deliver_intr (int line, ipc_port_t dest_port); +queue_head_t main_intr_queue; -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, int id, 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) && (e->id == id)) return e; } return NULL; } -static struct intr_entry * -search_intr_line (int line) +static user_intr_t * +search_intr_id (struct irqdev *dev, int id) { - 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->line == line && - (e->dest != MACH_PORT_NULL - && e->dest->ip_references != 1 - && e->unacked_interrupts)) - return e; + if (e->id == id && + (e->dst_port != MACH_PORT_NULL + && e->dst_port->ip_references != 1 + && e->n_unacked)) + return e; } return NULL; } -kern_return_t user_intr_enable (int line, char status) + +/* This function can only be used in the interrupt handler. */ +static void +queue_intr (struct irqdev *dev, int id, user_intr_t *e) { - struct intr_entry *e; - kern_return_t ret = D_SUCCESS; + /* Until userland has handled the IRQ in the driver, we have to keep it + * disabled. Level-triggered interrupts would keep raising otherwise. */ + irq_disable (dev->irq[id]); 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->n_unacked++; + e->interrupts++; + dev->tot_num_intr++; + splx (s); + + thread_wakeup ((event_t) &intr_thread); +} + +static boolean_t +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) dst_port; + + if (dest == MACH_PORT_NULL) + return FALSE; + + kmsg = ikm_alloc(sizeof *n); + if (kmsg == IKM_NULL) + return FALSE; + + ikm_init(kmsg, sizeof *n); + n = (device_intr_notification_t *) &kmsg->ikm_header; + + 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_size = sizeof *n; + m->msgh_seqno = DEVICE_NOTIFY_MSGH_SEQNO; + m->msgh_local_port = MACH_PORT_NULL; + m->msgh_remote_port = MACH_PORT_NULL; + m->msgh_id = DEVICE_INTR_NOTIFY; + + t->msgt_name = MACH_MSG_TYPE_INTEGER_32; + t->msgt_size = 32; + t->msgt_number = 1; + t->msgt_inline = TRUE; + t->msgt_longform = FALSE; + t->msgt_deallocate = FALSE; + t->msgt_unused = 0; + + n->intr_header.msgh_remote_port = dest; + n->id = id; + + ipc_port_copy_send (dst_port); + ipc_mqueue_send_always(kmsg); + + return TRUE; +} + +kern_return_t +irq_acknowledge (int id) +{ + 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_id */ + e = search_intr_id (&irqtab, id); 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 %d!?\n", id); 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); - return D_SUCCESS; -} - -/* This function can only be used in the interrupt handler. */ -static void -queue_intr (int line, 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); + if (irqtab.irqdev_ack) + (*(irqtab.irqdev_ack)) (&irqtab, id); - spl_t s = splhigh (); - e->unacked_interrupts++; - e->interrupts++; - tot_num_intr++; - splx (s); + irq_enable (irqtab.irq[id]); - thread_wakeup ((event_t) &intr_thread); + return D_SUCCESS; } -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; } } @@ -122,37 +158,37 @@ 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, id, 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 + /* XXX 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; + new->n_unacked = 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) @@ -163,10 +199,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 (;;) { @@ -176,11 +212,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 @@ -188,24 +224,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--; + irq_enable (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; @@ -215,13 +251,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 (); } } @@ -229,16 +265,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--; + irq_enable (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 (); @@ -249,47 +285,4 @@ intr_thread (void) } } -static boolean_t -deliver_intr (int line, ipc_port_t dest_port) -{ - ipc_kmsg_t kmsg; - device_intr_notification_t *n; - mach_port_t dest = (mach_port_t) dest_port; - - if (dest == MACH_PORT_NULL) - return FALSE; - - kmsg = ikm_alloc(sizeof *n); - if (kmsg == IKM_NULL) - return FALSE; - - ikm_init(kmsg, sizeof *n); - n = (device_intr_notification_t *) &kmsg->ikm_header; - - 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_size = sizeof *n; - m->msgh_seqno = DEVICE_NOTIFY_MSGH_SEQNO; - m->msgh_local_port = MACH_PORT_NULL; - m->msgh_remote_port = MACH_PORT_NULL; - m->msgh_id = DEVICE_INTR_NOTIFY; - - t->msgt_name = MACH_MSG_TYPE_INTEGER_32; - t->msgt_size = 32; - t->msgt_number = 1; - t->msgt_inline = TRUE; - t->msgt_longform = FALSE; - t->msgt_deallocate = FALSE; - t->msgt_unused = 0; - - n->intr_header.msgh_remote_port = dest; - n->line = line; - - ipc_port_copy_send (dest_port); - ipc_mqueue_send_always(kmsg); - - return TRUE; -} #endif /* MACH_XEN */ diff --git a/device/irq.h b/device/irq.h new file mode 100644 index 00000000..0e5e42a6 --- /dev/null +++ b/device/irq.h @@ -0,0 +1,48 @@ +#ifndef _DEVICE_IRQ_H +#define _DEVICE_IRQ_H + +#ifndef MACH_XEN + +#include +#include +#include +#include +#include + +#define DEVICE_NOTIFY_MSGH_SEQNO 0 + +#include + +struct irqdev; +#include + +typedef struct { + queue_chain_t chain; + 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; + +struct irqdev { + char *name; + void (*irqdev_ack)(struct irqdev *dev, int id); + + queue_head_t *intr_queue; + int tot_num_intr; /* Total number of unprocessed interrupts */ + + /* Machine dependent */ + irq_t irq[NINTR]; +}; + +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 (int id); + +#endif /* MACH_XEN */ + +#endif diff --git a/i386/Makefrag.am b/i386/Makefrag.am index f38c0785..59571416 100644 --- a/i386/Makefrag.am +++ b/i386/Makefrag.am @@ -102,6 +102,8 @@ libkernel_a_SOURCES += \ i386/i386/io_perm.c \ i386/i386/io_perm.h \ i386/i386/ipl.h \ + i386/i386/irq.c \ + i386/i386/irq.h \ i386/i386/ktss.c \ i386/i386/ktss.h \ i386/i386/kttd_interface.c \ diff --git a/i386/i386/irq.c b/i386/i386/irq.c new file mode 100644 index 00000000..0657f5fd --- /dev/null +++ b/i386/i386/irq.c @@ -0,0 +1,30 @@ +#include +#include +#include +#include + +extern queue_head_t main_intr_queue; + +static void +irq_eoi (struct irqdev *dev, int id) +{ + /* TODO EOI(dev->irq[id]) */ +} + +void +irq_enable (irq_t irq) +{ + unmask_irq (irq); +} + +void +irq_disable (irq_t irq) +{ + mask_irq (irq); +} + +struct irqdev irqtab = { + "irq", irq_eoi, &main_intr_queue, 0, + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, +}; + diff --git a/i386/i386/irq.h b/i386/i386/irq.h new file mode 100644 index 00000000..12bc00d6 --- /dev/null +++ b/i386/i386/irq.h @@ -0,0 +1,13 @@ +#ifndef _I386_IRQ_H +#define _I386_IRQ_H + +#include + +typedef unsigned int irq_t; + +void irq_enable (irq_t irq); +void irq_disable (irq_t irq); + +extern struct irqdev irqtab; + +#endif diff --git a/i386/i386/pic.c b/i386/i386/pic.c index 0feebc6f..3c0e7d91 100644 --- a/i386/i386/pic.c +++ b/i386/i386/pic.c @@ -185,3 +185,57 @@ intnull(int unit_dev) } } + +/* + * Mask a PIC IRQ. + */ +inline void +mask_irq (unsigned int irq_nr) +{ + int new_pic_mask = curr_pic_mask | 1 << irq_nr; + + if (curr_pic_mask != new_pic_mask) + { + curr_pic_mask = new_pic_mask; + if (irq_nr < 8) + { + outb (PIC_MASTER_OCW, curr_pic_mask & 0xff); + } + else + { + outb (PIC_SLAVE_OCW, curr_pic_mask >> 8); + } + } +} + +/* + * Unmask a PIC IRQ. + */ +inline void +unmask_irq (unsigned int irq_nr) +{ + int mask; + int new_pic_mask; + + mask = 1 << irq_nr; + if (irq_nr >= 8) + { + mask |= 1 << 2; + } + + new_pic_mask = curr_pic_mask & ~mask; + + if (curr_pic_mask != new_pic_mask) + { + curr_pic_mask = new_pic_mask; + if (irq_nr < 8) + { + outb (PIC_MASTER_OCW, curr_pic_mask & 0xff); + } + else + { + outb (PIC_SLAVE_OCW, curr_pic_mask >> 8); + } + } +} + diff --git a/i386/i386/pic.h b/i386/i386/pic.h index 553c4bcc..01fc5ccc 100644 --- a/i386/i386/pic.h +++ b/i386/i386/pic.h @@ -180,6 +180,8 @@ WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. extern void picinit (void); extern int curr_pic_mask; extern void intnull(int unit); +extern inline void mask_irq (unsigned int irq_nr); +extern inline void unmask_irq (unsigned int irq_nr); #endif /* __ASSEMBLER__ */ #endif /* _I386_PIC_H_ */ diff --git a/i386/i386at/conf.c b/i386/i386at/conf.c index fe7c7c09..6a84daab 100644 --- a/i386/i386at/conf.c +++ b/i386/i386at/conf.c @@ -68,6 +68,9 @@ #define hypcnname "hyp" #endif /* MACH_HYP */ +#include +#define irqname "irq" + /* * List of devices - console must be at slot 0 */ @@ -149,6 +152,11 @@ struct dev_ops dev_name_list[] = nodev }, #endif /* MACH_HYP */ + { irqname, nulldev_open, nulldev_close, nulldev_read, + nulldev_write,nulldev_getstat,nulldev_setstat, nomap, + nodev, nulldev, nulldev_portdeath,0, + nodev }, + }; int dev_name_count = sizeof(dev_name_list)/sizeof(dev_name_list[0]); diff --git a/include/device/device.defs b/include/device/device.defs index dca1be4e..78416a59 100644 --- a/include/device/device.defs +++ b/include/device/device.defs @@ -143,22 +143,20 @@ routine device_set_filter( ); routine device_intr_register( - master_port : mach_port_t; - in line : int; + device : device_t; in id : int; in flags : int; in receive_port : mach_port_send_t ); /* - * enable/disable the specified line. + * enable the specified irq id + */ +/* AIUI, the kernel IRQ handler should always disable the line + * and the userspace driver only has to reenable it, + * after acknowledging and handling the interrupt... */ -/* XXX: Naming a function taht can disable something "xxx_enable" is confusing. */ -/* Is the disable part actually used at all? AIUI, the kernel IRQ handler -should always disable the line; and the userspace driver only has to -reenable it, after acknowledging and handling the interrupt... -*/ routine device_intr_enable( - master_port : mach_port_t; - line : int; - status : char); + device : device_t; + in id : int); + diff --git a/include/device/notify.defs b/include/device/notify.defs index ea374d26..7919b339 100644 --- a/include/device/notify.defs +++ b/include/device/notify.defs @@ -33,4 +33,4 @@ serverdemux device_intr_notify_server; simpleroutine device_intr_notify( notify : notify_port_t; - name : int); + id : int); diff --git a/include/device/notify.h b/include/device/notify.h index b6907b03..addf9114 100644 --- a/include/device/notify.h +++ b/include/device/notify.h @@ -26,7 +26,7 @@ typedef struct { mach_msg_header_t intr_header; mach_msg_type_t intr_type; - int line; + int id; } device_intr_notification_t; #define DEVICE_INTR_NOTIFY 100 diff --git a/kern/startup.c b/kern/startup.c index 1f873192..c8ab182d 100644 --- a/kern/startup.c +++ b/kern/startup.c @@ -63,7 +63,7 @@ #include #include #include -#include +#include #if MACH_KDB #include diff --git a/linux/dev/arch/i386/kernel/irq.c b/linux/dev/arch/i386/kernel/irq.c index bc752013..04a635bc 100644 --- a/linux/dev/arch/i386/kernel/irq.c +++ b/linux/dev/arch/i386/kernel/irq.c @@ -50,7 +50,7 @@ #include #include -#include +#include #if 0 /* XXX: This is the way it's done in linux 2.2. GNU Mach currently uses intr_count. It should be made using local_{bh/irq}_count instead (through hardirq_enter/exit) for SMP support. */ @@ -89,49 +89,6 @@ static struct linux_action *irq_action[16] = NULL, NULL, NULL, NULL }; -/* - * Mask an IRQ. - */ -static inline void -mask_irq (unsigned int irq_nr) -{ - int new_pic_mask = curr_pic_mask | 1 << irq_nr; - - if (curr_pic_mask != new_pic_mask) - { - curr_pic_mask = new_pic_mask; - if (irq_nr < 8) - outb (curr_pic_mask & 0xff, PIC_MASTER_OCW); - else - outb (curr_pic_mask >> 8, PIC_SLAVE_OCW); - } -} - -/* - * Unmask an IRQ. - */ -static inline void -unmask_irq (unsigned int irq_nr) -{ - int mask; - int new_pic_mask; - - mask = 1 << irq_nr; - if (irq_nr >= 8) - mask |= 1 << 2; - - new_pic_mask = curr_pic_mask & ~mask; - - if (curr_pic_mask != new_pic_mask) - { - curr_pic_mask = new_pic_mask; - if (irq_nr < 8) - outb (curr_pic_mask & 0xff, PIC_MASTER_OCW); - else - outb (curr_pic_mask >> 8, PIC_SLAVE_OCW); - } -} - /* * Generic interrupt handler for Linux devices. * Set up a fake `struct pt_regs' then call the real handler. @@ -157,7 +114,7 @@ linux_intr (int irq) // the current device. But I don't do it for now. if (action->user_intr) { - if (!deliver_user_intr(irq, action->user_intr)) + if (!deliver_user_intr(&irqtab, irq, action->user_intr)) { *prev = action->next; linux_kfree(action); @@ -300,13 +257,15 @@ setup_x86_irq (int irq, struct linux_action *new) } int -install_user_intr_handler (unsigned int irq, unsigned long flags, +install_user_intr_handler (struct irqdev *dev, int id, unsigned long flags, user_intr_t *user_intr) { struct linux_action *action; struct linux_action *old; int retval; + unsigned int irq = dev->irq[id]; + assert (irq < 16); /* Test whether the irq handler has been set */ @@ -314,7 +273,7 @@ install_user_intr_handler (unsigned int irq, unsigned long flags, old = irq_action[irq]; while (old) { - if (old->user_intr && old->user_intr->dest == user_intr->dest) + if (old->user_intr && old->user_intr->dst_port == user_intr->dst_port) { printk ("The interrupt handler has already been installed on line %d", irq); return linux_to_mach_error (-EAGAIN); -- 2.25.1