|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH v3 12/24] xen/arm: Release IRQ routed to a domain when it's destroying
On Tue, 13 Jan 2015, Julien Grall wrote:
> Xen has to release IRQ routed to a domain in order to reuse later. Currently
> only SPIs can be routed to the guest so we only need to browse SPIs for a
> specific domain.
>
> Futhermore, a guest can crash and let the IRQ in an incorrect state (i.e has
> not being EOIed). Xen will have to reset the IRQ in order to be able to reuse
> the IRQ later.
>
> Introduce 2 new functions for release an IRQ routed to a domain:
> - release_guest_irq: upper level to retrieve the IRQ, call the GIC
> code and release the action
> - gic_remove_guest_irq: Check if we can remove the IRQ, and reset
> it if necessary
>
> Signed-off-by: Julien Grall <julien.grall@xxxxxxxxxx>
Acked-by: Stefano Stabellini <stefano.stabellini@xxxxxxxxxxxxx>
> ---
> Changes in v3:
> - Take the vgic rank lock to protect p->desc
> - Correctly check if the IRQ is disabled
> - Extend the check on the virq in release_guest_irq
> - Use vgic_get_target_vcpu to get the target vCPU
> - Remove spurious change
>
> Changes in v2:
> - Drop the desc->handler = &no_irq_type in release_irq as it's
> buggy if the IRQ is routed to Xen
> - Add release_guest_irq and gic_remove_guest_irq
> ---
> xen/arch/arm/gic.c | 46 +++++++++++++++++++++++++++++++++++++++++++++
> xen/arch/arm/irq.c | 48
> +++++++++++++++++++++++++++++++++++++++++++++++
> xen/arch/arm/vgic.c | 16 ++++++++++++++++
> xen/include/asm-arm/gic.h | 4 ++++
> xen/include/asm-arm/irq.h | 2 ++
> 5 files changed, 116 insertions(+)
>
> diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c
> index 240870f..bb298e9 100644
> --- a/xen/arch/arm/gic.c
> +++ b/xen/arch/arm/gic.c
> @@ -162,6 +162,52 @@ out:
> return res;
> }
>
> +/* This function only works with SPIs for now */
> +int gic_remove_irq_from_guest(struct domain *d, unsigned int virq,
> + struct irq_desc *desc)
> +{
> + struct vcpu *v_target = vgic_get_target_vcpu(d->vcpu[0], virq);
> + struct vgic_irq_rank *rank = vgic_rank_irq(v_target, virq);
> + struct pending_irq *p = irq_to_pending(v_target, virq);
> + unsigned long flags;
> +
> + ASSERT(spin_is_locked(&desc->lock));
> + ASSERT(test_bit(_IRQ_GUEST, &desc->status));
> + ASSERT(p->desc == desc);
> +
> + vgic_lock_rank(v_target, rank, flags);
> +
> + /* If the IRQ is removed when the domain is dying, we only need to
> + * EOI the IRQ if it has not been done by the guest
> + */
> + if ( d->is_dying )
> + {
> + desc->handler->shutdown(desc);
> + if ( test_bit(_IRQ_INPROGRESS, &desc->status) )
> + gic_hw_ops->deactivate_irq(desc);
> + clear_bit(_IRQ_INPROGRESS, &desc->status);
> + goto end;
> + }
> +
> + /* TODO: Handle eviction from LRs. For now, deny remove if the IRQ
> + * is inflight and not disabled.
> + */
> + if ( test_bit(_IRQ_INPROGRESS, &desc->status) ||
> + !test_bit(_IRQ_DISABLED, &desc->status) )
> + return -EBUSY;
> +
> +end:
> + clear_bit(_IRQ_GUEST, &desc->status);
> + desc->handler = &no_irq_type;
> +
> + p->desc = NULL;
> +
> + vgic_unlock_rank(v_target, rank, flags);
> +
> +
> + return 0;
> +}
> +
> int gic_irq_xlate(const u32 *intspec, unsigned int intsize,
> unsigned int *out_hwirq,
> unsigned int *out_type)
> diff --git a/xen/arch/arm/irq.c b/xen/arch/arm/irq.c
> index 0072347..ce5ae1a 100644
> --- a/xen/arch/arm/irq.c
> +++ b/xen/arch/arm/irq.c
> @@ -504,6 +504,54 @@ free_info:
> return retval;
> }
>
> +int release_guest_irq(struct domain *d, unsigned int virq)
> +{
> + struct irq_desc *desc;
> + struct irq_guest *info;
> + unsigned long flags;
> + struct pending_irq *p;
> + int ret;
> +
> + /* Only SPIs are supported */
> + if ( virq < 32 || virq >= vgic_num_irqs(d) )
> + return -EINVAL;
> +
> + p = irq_to_pending(d->vcpu[0], virq);
> + if ( !p->desc )
> + return -EINVAL;
> +
> + desc = p->desc;
> +
> + spin_lock_irqsave(&desc->lock, flags);
> +
> + ret = -EINVAL;
> + if ( !test_bit(_IRQ_GUEST, &desc->status) )
> + goto unlock;
> +
> + ret = -EINVAL;
> +
> + info = irq_get_guest_info(desc);
> + if ( d != info->d )
> + goto unlock;
> +
> + ret = gic_remove_irq_from_guest(d, virq, desc);
> +
> + spin_unlock_irqrestore(&desc->lock, flags);
> +
> + if ( !ret )
> + {
> + release_irq(desc->irq, info);
> + xfree(info);
> + }
> +
> + return ret;
> +
> +unlock:
> + spin_unlock_irqrestore(&desc->lock, flags);
> +
> + return ret;
> +}
> +
> /*
> * pirq event channels. We don't use these on ARM, instead we use the
> * features of the GIC to inject virtualised normal interrupts.
> diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c
> index fc8a270..4ddfd73 100644
> --- a/xen/arch/arm/vgic.c
> +++ b/xen/arch/arm/vgic.c
> @@ -133,6 +133,22 @@ void register_vgic_ops(struct domain *d, const struct
> vgic_ops *ops)
>
> void domain_vgic_free(struct domain *d)
> {
> + int i;
> + int ret;
> +
> + for ( i = 0; i < (d->arch.vgic.nr_spis); i++ )
> + {
> + struct pending_irq *p = &d->arch.vgic.pending_irqs[i];
> +
> + if ( p->desc )
> + {
> + ret = release_guest_irq(d, p->irq);
> + if ( ret )
> + dprintk(XENLOG_G_WARNING, "d%u: Failed to release virq %u
> ret = %d\n",
> + d->domain_id, p->irq, ret);
> + }
> + }
> +
> xfree(d->arch.vgic.shared_irqs);
> xfree(d->arch.vgic.pending_irqs);
> xfree(d->arch.vgic.allocated_irqs);
> diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h
> index a8ac294..5571189 100644
> --- a/xen/include/asm-arm/gic.h
> +++ b/xen/include/asm-arm/gic.h
> @@ -217,6 +217,10 @@ extern int gic_route_irq_to_guest(struct domain *,
> unsigned int virq,
> struct irq_desc *desc,
> unsigned int priority);
>
> +/* Remove an IRQ passthrough to a guest */
> +int gic_remove_irq_from_guest(struct domain *d, unsigned int virq,
> + struct irq_desc *desc);
> +
> extern void gic_inject(void);
> extern void gic_clear_pending_irqs(struct vcpu *v);
> extern int gic_events_need_delivery(void);
> diff --git a/xen/include/asm-arm/irq.h b/xen/include/asm-arm/irq.h
> index 71b39e7..34b492b 100644
> --- a/xen/include/asm-arm/irq.h
> +++ b/xen/include/asm-arm/irq.h
> @@ -44,6 +44,8 @@ void init_secondary_IRQ(void);
>
> int route_irq_to_guest(struct domain *d, unsigned int virq,
> unsigned int irq, const char *devname);
> +int release_guest_irq(struct domain *d, unsigned int irq);
> +
> void arch_move_irqs(struct vcpu *v);
>
> /* Set IRQ type for an SPI */
> --
> 2.1.4
>
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |