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