From: Jan Kiszka <jan.kis...@siemens.com>

This patch allows to optionally attach a message to an IRQ event. The
message can contain a payload reference and a callback that the IRQ
handler may invoke to report the delivery result. The former can be used
to model message signaling interrupts, the latter to cleanly implement
IRQ de-coalescing logics.

Signed-off-by: Jan Kiszka <jan.kis...@siemens.com>
---
 hw/irq.c |   37 ++++++++++++++++++++++++++++++++++++-
 hw/irq.h |   38 +++++++++++++++++++++++++++++++++++++-
 2 files changed, 73 insertions(+), 2 deletions(-)

diff --git a/hw/irq.c b/hw/irq.c
index 24fb09d..db5136b 100644
--- a/hw/irq.c
+++ b/hw/irq.c
@@ -28,12 +28,31 @@ struct IRQState {
     qemu_irq_handler handler;
     void *opaque;
     int n;
+    IRQMsg *msg;
 };
 
-void qemu_set_irq(qemu_irq irq, int level)
+void qemu_set_irq_msg(qemu_irq irq, int level, IRQMsg *msg)
 {
     if (irq) {
+        irq->msg = msg;
         irq->handler(irq, irq->opaque, irq->n, level);
+        irq->msg = NULL;
+    }
+}
+
+void *qemu_irq_get_payload(qemu_irq irq)
+{
+    IRQMsg *msg = irq->msg;
+
+    return msg ? msg->payload : NULL;
+}
+
+void qemu_irq_fire_delivery_cb(qemu_irq irq, int level, int result)
+{
+    IRQMsg *msg = irq->msg;
+
+    if (msg && msg->delivery_cb) {
+        msg->delivery_cb(irq, msg->delivery_opaque, irq->n, level, result);
     }
 }
 
@@ -61,11 +80,27 @@ void qemu_free_irqs(qemu_irq *s)
     qemu_free(s);
 }
 
+static void qemu_notirq_delivery_cb(qemu_irq irq, void *opaque, int line,
+                                    int level, int result)
+{
+    qemu_irq orig_irq = opaque;
+
+    qemu_irq_fire_delivery_cb(orig_irq, !level, result);
+}
+
 static void qemu_notirq(qemu_irq irq, void *opaque, int line, int level)
 {
     struct IRQState *inv_irq = opaque;
+    IRQMsg msg;
 
+    if (irq->msg) {
+        msg.delivery_cb = qemu_notirq_delivery_cb;
+        msg.delivery_opaque = irq;
+        msg.payload = irq->msg->payload;
+        inv_irq->msg = &msg;
+    }
     inv_irq->handler(inv_irq, inv_irq->opaque, inv_irq->n, !level);
+    inv_irq->msg = NULL;
 }
 
 qemu_irq qemu_irq_invert(qemu_irq irq)
diff --git a/hw/irq.h b/hw/irq.h
index d0f83e3..01f96af 100644
--- a/hw/irq.h
+++ b/hw/irq.h
@@ -3,26 +3,62 @@
 
 /* Generic IRQ/GPIO pin infrastructure.  */
 
+#define QEMU_IRQ_DELIVERED      0
+#define QEMU_IRQ_COALESCED      (-1)
+#define QEMU_IRQ_MASKED         (-2)
+
+typedef void (*qemu_irq_delivery_cb)(qemu_irq irq, void *opaque, int n,
+                                     int level, int result);
 typedef void (*qemu_irq_handler)(qemu_irq irq, void *opaque, int n, int level);
 
-void qemu_set_irq(qemu_irq irq, int level);
+typedef struct IRQMsg {
+    qemu_irq_delivery_cb delivery_cb;
+    void *delivery_opaque;
+    void *payload;
+} IRQMsg;
+
+void qemu_set_irq_msg(qemu_irq irq, int level, IRQMsg *msg);
+
+static inline void qemu_set_irq(qemu_irq irq, int level)
+{
+    qemu_set_irq_msg(irq, level, NULL);
+}
 
 static inline void qemu_irq_raise(qemu_irq irq)
 {
     qemu_set_irq(irq, 1);
 }
 
+static inline void qemu_irq_raise_msg(qemu_irq irq, IRQMsg *msg)
+{
+    qemu_set_irq_msg(irq, 1, msg);
+}
+
 static inline void qemu_irq_lower(qemu_irq irq)
 {
     qemu_set_irq(irq, 0);
 }
 
+static inline void qemu_irq_lower_msg(qemu_irq irq, IRQMsg *msg)
+{
+    qemu_set_irq_msg(irq, 0, msg);
+}
+
 static inline void qemu_irq_pulse(qemu_irq irq)
 {
     qemu_set_irq(irq, 1);
     qemu_set_irq(irq, 0);
 }
 
+static inline void qemu_irq_pulse_msg(qemu_irq irq, IRQMsg *msg)
+{
+    qemu_set_irq_msg(irq, 1, msg);
+    qemu_set_irq_msg(irq, 0, msg);
+}
+
+void qemu_irq_fire_delivery_cb(qemu_irq irq, int level, int result);
+void *qemu_irq_get_payload(qemu_irq irq);
+
 /* Returns an array of N IRQs.  */
 qemu_irq *qemu_allocate_irqs(qemu_irq_handler handler, void *opaque, int n);
 void qemu_free_irqs(qemu_irq *s);
-- 
1.6.0.2


Reply via email to