Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

[PATCH-2] A new irq device interface -- resend in plain text

0 views
Skip to first unread message

Junling Ma

unread,
Aug 2, 2020, 2:53:00 AM8/2/20
to bug-...@gnu.org
Sorry the previous PATCH-2 was not in plain text. Here is a resend.



Hi all,

In this patch, the new interface of irq device is implemented. Please see the first patch for a description.

Junling Ma

---
device/ds_routines.c | 2 +-
device/intr.c | 184 +++++++++++++++++++++++++++++++++----------
device/intr.h | 11 ++-
i386/i386at/conf.c | 4 +-
4 files changed, 154 insertions(+), 47 deletions(-)

diff --git a/device/ds_routines.c b/device/ds_routines.c
index 91787950..333b66c9 100644
--- a/device/ds_routines.c
+++ b/device/ds_routines.c
@@ -345,7 +345,7 @@ ds_device_intr_register (device_t dev, int id,

// TODO detect when the port get destroyed because the driver crashes and
// restart, to replace it when the same device driver calls it again.
- err = install_user_intr_handler (id, receive_port);
+ err = install_user_intr_handler (id, receive_port, mdev, FALSE);
if (err == D_SUCCESS)
{
/* If the port is installed successfully, increase its reference by 1.
diff --git a/device/intr.c b/device/intr.c
index 682b12d7..e78f2193 100644
--- a/device/intr.c
+++ b/device/intr.c
@@ -22,6 +22,7 @@
#include <ipc/ipc_space.h>
#include "io_req.h"
#include "ds_routines.h"
+#include "device.server.h"

#ifndef MACH_XEN

@@ -70,16 +71,20 @@ kern_return_t
irq_acknowledge (ipc_port_t receive_port)
{
user_intr_t *e;
+ user_intr_notification_t n = NULL;
unsigned id;
for (id = 0; id < NINTR; ++id)
{
e = irqtab.handler[id];
- if (e && search_notification (e, receive_port))
+ if (e && (n = search_notification (e, receive_port)) != NULL)
break;
}
- if (id == NINTR)
+ if (id == NINTR || n->device_port)
return D_INVALID_OPERATION;
-
+ /* cannot ack twice */
+ if (n->acked)
+ return D_INVALID_OPERATION;
+ n->acked = TRUE;
kern_return_t ret = D_SUCCESS;
PROTECT(e->lock,
{
@@ -105,16 +110,7 @@ deliver_user_intr (int id, void *dev_id, struct pt_regs *regs)
__disable_irq(id);
}
});
- if (!e) return;
- if (queue_empty(&e->notification_queue))
- {
- irqtab.handler[id] = NULL;
- if (e->n_unacked)
- __enable_irq (id);
- free_irq(id, &irqtab);
- e = NULL;
- }
- else if (e->interrupts)
+ if (e && !queue_empty(&e->notification_queue) && e->interrupts)
thread_wakeup ((event_t) &intr_thread);
}

@@ -137,43 +133,65 @@ intr_thread (void)
user_intr_t *e = irqtab.handler[id];
if (!e) continue;
clear_wait (current_thread (), 0, 0);
- user_intr_notification_t next;
- user_intr_notification_t n;
- /* go through each notification to fire or remove dead ones */
+ user_intr_notification_t next, n;
+ /* go through each notification to fire interrupts or remove dead ones */
PROTECT(e->lock,
{
+ boolean_t delivered = FALSE;
queue_iterate (&e->notification_queue, n, user_intr_notification_t, chain)
{
- /* is the notification port dead? */
- if (n->dst_port->ip_references == 1)
+ /* check for dead port */
+ while (n && n->dst_port->ip_references == 1)
{
/* dead, move it to the dead queue */
+ printf("dead port: %p\n", n->dst_port);
next = (user_intr_notification_t)queue_next(&n->chain);
queue_remove(&e->notification_queue, n, user_intr_notification_t, chain);
- ipc_port_release (n->dst_port);
- kfree((vm_offset_t)n, sizeof(*n));
- --e->n_unacked;
- if (e->n_unacked == 0)
- __enable_irq(id);
- printf("dead notification port %p released \n", n->dst_port);
- if (queue_empty(&e->notification_queue))
+ //ipc_port_release (n->dst_port);
+ if (n->request)
+ io_req_free(n->request);
+ /* if waiting for acking, ack it */
+ if (!n->acked && e->n_unacked)
{
- printf("irq %d has no registered notifications. remove\n", id);
- kfree((vm_offset_t)e, sizeof(*e));
- irqtab.handler[id] = NULL;
- break;
+ --e->n_unacked;
+ if (e->n_unacked == 0)
+ __enable_irq(id);
}
+ kfree((vm_offset_t)n, sizeof(*n));
+ ds_device_close(&n->device->dev);
n = next;
}
- else if (e->interrupts)
+ if (!n) break;
+ /* if there is a DEVICE, the notification uses the new interface */
+ /* the notification uses the old interface. is the notification port dead? */
+ if (!e->interrupts)
+ continue;
+ if (!n->device_port && !deliver_intr(id, n->dst_port))
+ continue; /* failed to delivery using the notification port */
+ if (n->device_port)
{
- SPLHIGH(e->interrupts--);
- total_interrupts += e->interrupts;
- if (deliver_intr(id, n->dst_port))
- /* n_unacked is increased when firing. Without firing, there is no ack */
- e->n_unacked++;
+ if (!n->request)
+ continue;
+ ds_read_done(n->request);
+ io_req_free(n->request);
}
+ n->request = NULL;
+ e->n_unacked++;
+ n->acked = FALSE;
+ delivered = TRUE;
} /* end of queue_iterate */
+ if (delivered) /* if successfully delivered */
+ {
+ SPLHIGH(e->interrupts--);
+ total_interrupts += e->interrupts;
+ }
+ if (queue_empty(&e->notification_queue))
+ {
+ printf("there is no registered handler for irq %d. close the device\n", id);
+ free_irq(id, &irqtab);
+ SPLHIGH(irqtab.handler[id] = NULL);
+ kfree((vm_offset_t)e, sizeof(*e));
+ }
}); /* end of PROTECT */
}
}
@@ -226,9 +244,9 @@ deliver_intr (int id, ipc_port_t dst_port)
}

int
-install_user_intr_handler (int id, ipc_port_t dst_port)
+install_user_intr_handler (int id, ipc_port_t dst_port, mach_device_t device, boolean_t device_port)
{
- if (id > NINTR || dst_port == NULL)
+ if (id > NINTR || device == NULL)
return D_INVALID_OPERATION;
user_intr_t *e = irqtab.handler[id];
if (e == NULL) {
@@ -243,7 +261,7 @@ install_user_intr_handler (int id, ipc_port_t dst_port)
/* install the new handler */
kern_return_t r = request_irq (id, deliver_user_intr, SA_SHIRQ, NULL, &irqtab);
if (r) {
- printf("could not register irq handler: %d(%08x)\n", r, r);
+ printf("could not register irq handler for irq %d: %d(%08x)\n", id, r, r);
irqtab.handler[id] = NULL;
kfree((vm_size_t)e, sizeof(*e));
return r;
@@ -253,18 +271,20 @@ install_user_intr_handler (int id, ipc_port_t dst_port)
/* check whether the intr entry has been in the queue. */
user_intr_notification_t n = search_notification (e, dst_port);
if (n)
- {
- printf ("the interrupt entry for irq %d and port %p has already been inserted\n", id, dst_port);
- return D_ALREADY_OPEN;
- }
+ return D_ALREADY_OPEN;

n = (user_intr_notification_t) kalloc (sizeof (*n));
if (n == NULL)
return D_NO_MEMORY;

n->dst_port = dst_port;
+ ipc_port_reference(dst_port);
+ n->device = device;
+ n->device_port = device_port;
+ n->request = NULL;
+ n->acked = TRUE;
PROTECT(e->lock, queue_enter (&e->notification_queue, n, user_intr_notification_t, chain));
- printf("irq handler [%d]: new delivery port %p\n", id, dst_port);
+ printf("notification port %p register for irq %d\n", dst_port, id);
return D_SUCCESS;
}

@@ -275,4 +295,82 @@ void irq_init()
irqtab.handler[i] = NULL;
}

+extern int irqopen(dev_t dev, int flag, io_req_t ior)
+{
+ int id = minor(dev);
+ /* for now, we need to handle opening "irq", which is the same as irq0
+ this is for backward compatibility. */
+ if (id == 0)
+ return D_SUCCESS;
+ if (id > NINTR)
+ return D_NO_SUCH_DEVICE;
+ user_intr_t *e = irqtab.handler[id];
+ if (e)
+ return D_SUCCESS;
+ ior->io_error = D_SUCCESS;
+ return install_user_intr_handler (id, ior->io_reply_port, ior->io_device, TRUE);
+}
+
+void irqclose(dev_t dev, int flags)
+{
+ /* device closes are handled by port death detection */
+}
+
+extern int irqread(dev_t dev, io_req_t ior)
+{
+ irq_t id = minor(dev);
+ if (id > NINTR)
+ return D_NO_SUCH_DEVICE;
+ user_intr_t *e = irqtab.handler[id];
+ user_intr_notification_t n = NULL;
+ if (e)
+ n = search_notification(e, ior->io_reply_port);
+ if (!n)
+ {
+ int err = install_user_intr_handler(id, ior->io_reply_port, ior->io_device, TRUE);
+ if (err)
+ return err;
+ e = irqtab.handler[id];
+ n = search_notification(e, ior->io_reply_port);
+ }
+ /* already requested */
+ if (n->request || !n->acked)
+ return D_INVALID_OPERATION;
+ n->request = ior;
+ ior->io_error = D_SUCCESS;
+ ior->io_residual = ior->io_count;
+ return D_IO_QUEUED;
+}
+
+extern int irqwrite(dev_t dev, io_req_t ior)
+{
+ irq_t id = minor(dev);
+ if (id > NINTR)
+ return D_NO_SUCH_DEVICE;
+ user_intr_t *e = irqtab.handler[id];
+ if (e == NULL)
+ return D_DEVICE_DOWN;
+ if (e->n_unacked == 0)
+ return D_INVALID_OPERATION;
+ user_intr_notification_t n = search_notification(e, ior->io_reply_port);
+ if (!n || n->request || n->acked)
+ return D_INVALID_OPERATION;
+ n->acked = TRUE;
+ PROTECT(e->lock,
+ {
+ e->n_unacked--;
+ if (e->n_unacked == 0)
+ __enable_irq(id);
+ });
+ boolean_t wait = FALSE;
+ int rc = device_write_get(ior, &wait);
+ if (rc != KERN_SUCCESS)
+ return rc;
+ if (wait)
+ return D_INVALID_OPERATION;
+ ior->io_residual = ior->io_count;
+ ior->io_error = D_SUCCESS;
+ return D_SUCCESS;
+}
+
#endif /* MACH_XEN */
diff --git a/device/intr.h b/device/intr.h
index 90bc6f4c..88b40516 100644
--- a/device/intr.h
+++ b/device/intr.h
@@ -33,7 +33,11 @@ struct irqdev;
/* a struct to hold notifications */
struct user_intr_notification {
queue_chain_t chain;
+ io_req_t request;
+ boolean_t acked;
+ mach_device_t device;
ipc_port_t dst_port; /* Notification port */
+ boolean_t device_port; /* whether dst_port is a device port, i.e, using the new interface */
};
typedef struct user_intr_notification * user_intr_notification_t;

@@ -49,12 +53,17 @@ struct irqdev {
user_intr_t *handler[NINTR]; /* irq handlers for device_open */
};

-extern int install_user_intr_handler (int id, ipc_port_t dst_port);
+extern int install_user_intr_handler (int id, ipc_port_t dst_port, mach_device_t device, boolean_t device_port);
extern void irq_init();

void intr_thread (void);
kern_return_t irq_acknowledge (ipc_port_t receive_port);

+extern int irqopen(dev_t dev, int flag, io_req_t ior);
+extern void irqclose(dev_t dev, int flags);
+extern int irqread(dev_t dev, io_req_t ior);
+extern int irqwrite(dev_t dev, io_req_t ior);
+
#endif /* MACH_XEN */

#endif
diff --git a/i386/i386at/conf.c b/i386/i386at/conf.c
index ca5d0dfb..69f12ae2 100644
--- a/i386/i386at/conf.c
+++ b/i386/i386at/conf.c
@@ -152,8 +152,8 @@ struct dev_ops dev_name_list[] =
nodev },
#endif /* MACH_HYP */

- { irqname, nulldev_open, nulldev_close, nulldev_read,
- nulldev_write,nulldev_getstat,nulldev_setstat, nomap,
+ { irqname, irqopen, irqclose, irqread,
+ irqwrite,nulldev_getstat,nulldev_setstat, nomap,
nodev, nulldev, nulldev_portdeath,0,
nodev },

--
2.28.0.rc1


Samuel Thibault

unread,
Aug 2, 2020, 5:01:42 PM8/2/20
to Junling Ma, bug-...@gnu.org
Junling Ma, le sam. 01 août 2020 19:04:05 -0700, a ecrit:
> In this patch, the new interface of irq device is implemented. Please see the first patch for a description.

Not only, it also brings other changes, making the patch unreviewable.

Samuel

Samuel Thibault

unread,
Aug 2, 2020, 5:05:24 PM8/2/20
to Junling Ma, bug-...@gnu.org
Could you also send a patch that fixes libddekit? Otherwise, again, I
can't apply your patches.

Until I would happen to magically find the time to fix libddekit myself
of course.

Samuel

0 new messages