On 5/7/20 3:48 am, Samuel Thibault wrote:
> Hello,
>
> Thanks for reworking this! With a couple RPC interface changes we can
> probably commit it.
Hooray!
> I.e. remove this disable and initial unacked interrupt, and remove the
> initial intr_enable call from netdde / rump.
>
Done in this patch. (not the netdde/rump part yet)
>> -ds_device_intr_enable(ipc_port_t master_port, int line, char status)
>> +ds_device_intr_enable (device_t dev, int id)
>
> Please rename to ds_device_intr_ack, we don't want to keep an underlying
> intr disable/enable semantic (notably since you are dropping the status
> parameter).
ACK
> Also, as mentioned in the previous user_intr_enable() prototype, this
> RPC should be taking the delivery port rather than the irq id, so we use
> search_intr instead of search_intr_line.
ACK
> The smaller the patch is, the less time it takes to review it, and thus
> the easier it is for me to find time to review it.
I've removed the unnecessary churn in the patch.
>> +void
>> +irq_enable (irq_t irq)
>> +{
>> + unmask_irq (irq);
>> +}
>
> This isn't enough: we need to disable irqs while doing this!
ACK
> Also, I don't think this will play nice with Linux drivers' own
> disabling counting management to properly share IRQs between
> Linux drivers and userland drivers. Why not just moving the
> __dis/enable_irq() functions from the Linux parT?
I don't want to mix linux/ code with pure mach code. The linux/
code will eventually be removed right? I think the linux interrupt handling
can remain counting interrupts separately.
One thing that is missing from this patch is the "vm_allocate_contiguous" RPC.
It is required for DMA. How should I proceed with it? Do I make it an RPC on
the
"mem" device only?
See attached for revised patch.
Thanks,
Damien
>From 072658e23208b4337f5d43c11244333e9798bdb2 Mon Sep 17 00:00:00 2001
From: Damien Zammit <[email protected]>
Date: Sun, 5 Jul 2020 11:15:44 +1000
Subject: [PATCH] irq: Refactor interrupts into mach device
---
device/dev_hdr.h | 9 ++
device/ds_routines.c | 66 +++++------
device/ds_routines.h | 3 -
device/intr.c | 183 +++++++++++++------------------
device/intr.h | 55 ++++++----
i386/Makefrag.am | 2 +
i386/i386/irq.c | 37 +++++++
i386/i386/irq.h | 14 +++
i386/i386/pic.c | 54 +++++++++
i386/i386/pic.h | 2 +
i386/i386at/conf.c | 8 ++
include/device/device.defs | 22 ++--
include/device/notify.defs | 2 +-
include/device/notify.h | 2 +-
linux/dev/arch/i386/kernel/irq.c | 51 +--------
15 files changed, 284 insertions(+), 226 deletions(-)
create mode 100644 i386/i386/irq.c
create mode 100644 i386/i386/irq.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..69e963bd 100644
--- a/device/ds_routines.c
+++ b/device/ds_routines.c
@@ -321,44 +321,35 @@ 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)
+ 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
@@ -1842,16 +1833,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 1e9ab898..eccc924f 100644
--- a/device/intr.c
+++ b/device/intr.c
@@ -1,119 +1,96 @@
#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);
+
+ irq_enable (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);
+ irq_disable (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;
}
}
@@ -122,37 +99,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)
@@ -163,10 +135,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 +148,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 +160,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 +187,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 +201,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 ();
@@ -250,11 +222,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;
@@ -285,11 +257,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 48843cf0..f3adebde 100644
--- a/device/intr.h
+++ b/device/intr.h
@@ -1,37 +1,48 @@
-#ifndef __INTR_H__
+#ifndef _DEVICE_IRQ_H
+#define _DEVICE_IRQ_H
-#define __INTR_H__
+#ifndef MACH_XEN
-#include <device/device_types.h>
+#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>
-typedef struct intr_entry
-{
+#define DEVICE_NOTIFY_MSGH_SEQNO 0
+
+#include <sys/types.h>
+
+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
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..11a2003d
--- /dev/null
+++ b/i386/i386/irq.c
@@ -0,0 +1,37 @@
+#include <i386/irq.h>
+#include <device/intr.h>
+#include <mach/kern_return.h>
+#include <kern/queue.h>
+#include <machine/machspl.h>
+
+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)
+{
+ spl_t s = splhigh();
+ mach_cli ();
+ unmask_irq (irq);
+ splx(s);
+}
+
+void
+irq_disable (irq_t irq)
+{
+ spl_t s = splhigh();
+ mach_cli ();
+ mask_irq (irq);
+ splx(s);
+}
+
+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..eb03c9cc
--- /dev/null
+++ b/i386/i386/irq.h
@@ -0,0 +1,14 @@
+#ifndef _I386_IRQ_H
+#define _I386_IRQ_H
+
+#include <i386/pic.h>
+#define mach_cli() __asm__ __volatile__ ("cli": : :"memory")
+
+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..ca5d0dfb 100644
--- a/i386/i386at/conf.c
+++ b/i386/i386at/conf.c
@@ -68,6 +68,9 @@
#define hypcnname "hyp"
#endif /* MACH_HYP */
+#include <device/intr.h>
+#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..ec4b5bf8 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.
+ * Acknowledge the specified interrupt notification.
*/
-/* 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);
+/*
+ * When an IRQ happens and an intr notification is thus sent, the IRQ line
+ * is kept disabled until the notification is acknowledged with this RPC
+ */
+routine device_intr_ack(
+ device : device_t;
+ in receive_port : mach_port_send_t);
+
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/linux/dev/arch/i386/kernel/irq.c b/linux/dev/arch/i386/kernel/irq.c
index bc752013..e7f50342 100644
--- a/linux/dev/arch/i386/kernel/irq.c
+++ b/linux/dev/arch/i386/kernel/irq.c
@@ -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