From: Andrii Anisov <andrii_ani...@epam.com> Do not put already disabled IRQs into any of queues, and remove an IRQ from all queues on disable. Insert the IRQ into queues on enable if needed. This also allows simplification of under-lock decission of events needed delivery.
Signed-off-by: Andrii Anisov <andrii_ani...@epam.com> --- xen/arch/arm/gic-vgic.c | 26 +++++++++----------------- xen/arch/arm/vgic.c | 28 +++++++++++++++++++++++++--- xen/include/asm-arm/vgic.h | 3 ++- 3 files changed, 36 insertions(+), 21 deletions(-) diff --git a/xen/arch/arm/gic-vgic.c b/xen/arch/arm/gic-vgic.c index 4e18169..9bbd0c5 100644 --- a/xen/arch/arm/gic-vgic.c +++ b/xen/arch/arm/gic-vgic.c @@ -87,10 +87,6 @@ void gic_raise_inflight_irq(struct vcpu *v, unsigned int virtual_irq) ASSERT(spin_is_locked(&v->arch.vgic.lock)); - /* Don't try to update the LR if the interrupt is disabled */ - if ( !test_bit(GIC_IRQ_GUEST_ENABLED, &n->status) ) - return; - if ( list_empty(&n->lr_queue) ) { if ( v == current ) @@ -366,6 +362,7 @@ int vgic_vcpu_pending_irq(struct vcpu *v) const unsigned long apr = gic_hw_ops->read_apr(0); int mask_priority; int active_priority; + int effective_priority; int rc = 0; /* We rely on reading the VMCR, which is only accessible locally. */ @@ -373,28 +370,23 @@ int vgic_vcpu_pending_irq(struct vcpu *v) mask_priority = gic_hw_ops->read_vmcr_priority(); active_priority = find_first_bit(&apr, 32); + effective_priority = min(mask_priority, active_priority); spin_lock_irqsave(&v->arch.vgic.lock, flags); /* TODO: We order the guest irqs by priority, but we don't change * the priority of host irqs. */ - /* find the first enabled non-active irq, the queue is already - * ordered by priority */ - list_for_each_entry( p, &v->arch.vgic.inflight_irqs, inflight ) + /* take the first non-active irq, the queue is already + * ordered by priority and has no disabled IRQs*/ + if ( !list_empty(&v->arch.vgic.inflight_irqs) ) { - if ( GIC_PRI_TO_GUEST(p->priority) >= mask_priority ) - goto out; - if ( GIC_PRI_TO_GUEST(p->priority) >= active_priority ) - goto out; - if ( test_bit(GIC_IRQ_GUEST_ENABLED, &p->status) ) - { - rc = 1; - goto out; - } + p = container_of(v->arch.vgic.inflight_irqs.next, struct pending_irq, + inflight); + if ( GIC_PRI_TO_GUEST(p->priority) < effective_priority ) + rc = 1; } -out: spin_unlock_irqrestore(&v->arch.vgic.lock, flags); return rc; } diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c index 37857b1..e30a518 100644 --- a/xen/arch/arm/vgic.c +++ b/xen/arch/arm/vgic.c @@ -364,6 +364,7 @@ void vgic_disable_irqs(struct vcpu *v, uint32_t r, int n) spin_lock_irqsave(&v_target->arch.vgic.lock, flags); p = irq_to_pending(v_target, irq); clear_bit(GIC_IRQ_GUEST_ENABLED, &p->status); + list_del_init(&p->inflight); gic_remove_from_lr_pending(v_target, p); desc = p->desc; spin_unlock_irqrestore(&v_target->arch.vgic.lock, flags); @@ -415,6 +416,23 @@ void vgic_enable_irqs(struct vcpu *v, uint32_t r, int n) spin_lock_irqsave(&v_target->arch.vgic.lock, flags); p = irq_to_pending(v_target, irq); set_bit(GIC_IRQ_GUEST_ENABLED, &p->status); + if ( test_bit(GIC_IRQ_GUEST_VISIBLE, &p->status) || + test_bit(GIC_IRQ_GUEST_QUEUED, &p->status) ) + { + struct pending_irq *iter; + p->priority = vgic_get_virq_priority(v, irq); + list_for_each_entry( iter, &v_target->arch.vgic.inflight_irqs, + inflight ) + { + if ( iter->priority > p->priority ) + { + list_add_tail(&p->inflight, &iter->inflight); + goto out; + } + } + list_add_tail(&p->inflight, &v_target->arch.vgic.inflight_irqs); + } +out: if ( !list_empty(&p->inflight) && !test_bit(GIC_IRQ_GUEST_VISIBLE, &p->status) ) gic_raise_guest_irq(v_target, irq, p->priority); spin_unlock_irqrestore(&v_target->arch.vgic.lock, flags); @@ -582,6 +600,12 @@ void vgic_inject_irq(struct domain *d, struct vcpu *v, unsigned int virq, set_bit(GIC_IRQ_GUEST_QUEUED, &n->status); + if ( !test_bit(GIC_IRQ_GUEST_ENABLED, &n->status) ) + {/*Do not insert a disabled IRQ into any queue*/ + spin_unlock_irqrestore(&v->arch.vgic.lock, flags); + return; + } + if ( !list_empty(&n->inflight) ) { gic_raise_inflight_irq(v, virq); @@ -591,9 +615,7 @@ void vgic_inject_irq(struct domain *d, struct vcpu *v, unsigned int virq, priority = vgic_get_virq_priority(v, virq); n->priority = priority; - /* the irq is enabled */ - if ( test_bit(GIC_IRQ_GUEST_ENABLED, &n->status) ) - gic_raise_guest_irq(v, virq, priority); + gic_raise_guest_irq(v, virq, priority); list_for_each_entry ( iter, &v->arch.vgic.inflight_irqs, inflight ) { diff --git a/xen/include/asm-arm/vgic.h b/xen/include/asm-arm/vgic.h index c5cb63f..7507162 100644 --- a/xen/include/asm-arm/vgic.h +++ b/xen/include/asm-arm/vgic.h @@ -58,7 +58,8 @@ struct pending_irq * irq is enabled at the vgicd level: * * GIC_IRQ_GUEST_ENABLED: the guest IRQ is enabled at the VGICD - * level (GICD_ICENABLER/GICD_ISENABLER). + * level (GICD_ICENABLER/GICD_ISENABLER). Disabled guest IRQ do not appear + * in an inflight queue * * GIC_IRQ_GUEST_MIGRATING: the irq is being migrated to a different * vcpu while it is still inflight and on an GICH_LR register on the -- 2.7.4 _______________________________________________ Xen-devel mailing list Xen-devel@lists.xenproject.org https://lists.xenproject.org/mailman/listinfo/xen-devel