From a767ebd126157c4aa55ff0fe5786681507fb7ea8 Mon Sep 17 00:00:00 2001 From: Jag Raman Date: Tue, 7 Jun 2022 16:21:40 -0400 Subject: irq: inform device of IRQ mask & unmask via callback (#694) Client masks or unmasks a device IRQ using the VFIO_USER_DEVICE_SET_IRQS message. Inform the device of such changes to the IRQ state. Signed-off-by: Jagannathan Raman Reviewed-by: John Levon --- lib/irq.c | 29 +++++++++++++++++++++++++++-- lib/libvfio-user.c | 16 ++++++++++++++++ lib/private.h | 1 + 3 files changed, 44 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/irq.c b/lib/irq.c index c7820aa..eadad7b 100644 --- a/lib/irq.c +++ b/lib/irq.c @@ -154,6 +154,32 @@ irqs_reset(vfu_ctx_t *vfu_ctx) } } +static void +irqs_set_state(vfu_ctx_t *vfu_ctx, struct vfio_irq_set *irq_set) +{ + vfu_dev_irq_state_cb_t *cb = NULL; + uint32_t irq_action; + bool mask = false; + + assert(irq_set->index < VFU_DEV_NUM_IRQS); + cb = vfu_ctx->irq_state_cbs[irq_set->index]; + if (cb == NULL) { + return; + } + + assert((irq_set->start + irq_set->count) <= + vfu_ctx->irq_count[irq_set->index]); + + irq_action = irq_set->flags & VFIO_IRQ_SET_ACTION_TYPE_MASK; + + assert((irq_action & VFIO_IRQ_SET_ACTION_MASK) || + (irq_action & VFIO_IRQ_SET_ACTION_UNMASK)); + + mask = (irq_action & VFIO_IRQ_SET_ACTION_MASK) ? true : false; + + cb(vfu_ctx, irq_set->start, irq_set->count, mask); +} + static int irqs_set_data_none(vfu_ctx_t *vfu_ctx, struct vfio_irq_set *irq_set) { @@ -345,8 +371,7 @@ handle_device_set_irqs(vfu_ctx_t *vfu_ctx, vfu_msg_t *msg) switch (irq_set->flags & VFIO_IRQ_SET_ACTION_TYPE_MASK) { case VFIO_IRQ_SET_ACTION_MASK: case VFIO_IRQ_SET_ACTION_UNMASK: - // We're always edge-triggered without un/mask support. - // FIXME: return an error? We don't report MASKABLE + irqs_set_state(vfu_ctx, irq_set); return 0; case VFIO_IRQ_SET_ACTION_TRIGGER: break; diff --git a/lib/libvfio-user.c b/lib/libvfio-user.c index 47e3572..c45ceeb 100644 --- a/lib/libvfio-user.c +++ b/lib/libvfio-user.c @@ -1968,6 +1968,22 @@ vfu_setup_device_nr_irqs(vfu_ctx_t *vfu_ctx, enum vfu_dev_irq_type type, } EXPORT int +vfu_setup_irq_state_callback(vfu_ctx_t *vfu_ctx, enum vfu_dev_irq_type type, + vfu_dev_irq_state_cb_t *cb) +{ + assert(vfu_ctx != NULL); + + if (type >= VFU_DEV_NUM_IRQS) { + vfu_log(vfu_ctx, LOG_ERR, "Invalid IRQ type index %u", type); + return ERROR_INT(EINVAL); + } + + vfu_ctx->irq_state_cbs[type] = cb; + + return 0; +} + +EXPORT int vfu_setup_device_migration_callbacks(vfu_ctx_t *vfu_ctx, const vfu_migration_callbacks_t *callbacks, uint64_t data_offset) diff --git a/lib/private.h b/lib/private.h index 4c483f2..7ffd6be 100644 --- a/lib/private.h +++ b/lib/private.h @@ -172,6 +172,7 @@ struct vfu_ctx { struct migration *migration; uint32_t irq_count[VFU_DEV_NUM_IRQS]; + vfu_dev_irq_state_cb_t *irq_state_cbs[VFU_DEV_NUM_IRQS]; vfu_irqs_t *irqs; bool realized; vfu_dev_type_t dev_type; -- cgit v1.1