|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH for-4.6 2/4] xen/arm: vgic: Keep track of vIRQ used by a domain
On Fri, 12 Dec 2014, Julien Grall wrote:
> While it's easy to know which hardware IRQ is assigned to a domain, there
> is no way to know which IRQ is emulated by Xen for a specific domain.
>
> Introduce a bitmap to keep track of every vIRQ used by a domain. This
> will be used later to find free vIRQ for interrupt device assignment and
> emulated interrupt.
>
> Signed-off-by: Julien Grall <julien.grall@xxxxxxxxxx>
> ---
> xen/arch/arm/domain_build.c | 6 +++
> xen/arch/arm/platforms/xgene-storm.c | 4 ++
> xen/arch/arm/vgic.c | 76
> ++++++++++++++++++++++++++++++++++++
> xen/arch/arm/vtimer.c | 15 +++++++
> xen/include/asm-arm/domain.h | 1 +
> xen/include/asm-arm/vgic.h | 13 ++++++
> 6 files changed, 115 insertions(+)
>
> diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
> index de180d8..c238c8f 100644
> --- a/xen/arch/arm/domain_build.c
> +++ b/xen/arch/arm/domain_build.c
> @@ -968,6 +968,12 @@ static int map_device(struct domain *d, struct
> dt_device_node *dev)
> irq = res;
>
> DPRINT("irq %u = %u\n", i, irq);
> + /*
> + * Checking the return of vgic_reserve_virq is not
> + * necessary. It should not fail except when we try to map
> + * twice the IRQ. This can happen if the IRQ is shared
> + */
> + vgic_reserve_virq(d, irq);
> res = route_irq_to_guest(d, irq, dt_node_name(dev));
> if ( res )
> {
> diff --git a/xen/arch/arm/platforms/xgene-storm.c
> b/xen/arch/arm/platforms/xgene-storm.c
> index 0b3492d..416d42c 100644
> --- a/xen/arch/arm/platforms/xgene-storm.c
> +++ b/xen/arch/arm/platforms/xgene-storm.c
> @@ -71,6 +71,10 @@ static int map_one_spi(struct domain *d, const char *what,
>
> printk("Additional IRQ %u (%s)\n", irq, what);
>
> + if ( !vgic_reserve_virq(d, irq) )
> + printk("Failed to reserve the vIRQ %u on dom%d\n",
> + irq, d->domain_id);
> +
> ret = route_irq_to_guest(d, irq, what);
> if ( ret )
> printk("Failed to route %s to dom%d\n", what, d->domain_id);
> diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c
> index 75cb7ff..dbfc259 100644
> --- a/xen/arch/arm/vgic.c
> +++ b/xen/arch/arm/vgic.c
> @@ -87,6 +87,8 @@ int domain_vgic_init(struct domain *d)
> return -ENODEV;
> }
>
> + spin_lock_init(&d->arch.vgic.lock);
you should probably explain in the commit message the reason why you are
making changes to the vgic lock
> d->arch.vgic.shared_irqs =
> xzalloc_array(struct vgic_irq_rank, DOMAIN_NR_RANKS(d));
> if ( d->arch.vgic.shared_irqs == NULL )
> @@ -107,6 +109,15 @@ int domain_vgic_init(struct domain *d)
>
> d->arch.vgic.handler->domain_init(d);
>
> + d->arch.vgic.allocated_irqs =
> + xzalloc_array(unsigned long, BITS_TO_LONGS(vgic_num_irqs(d)));
> + if ( !d->arch.vgic.allocated_irqs )
> + return -ENOMEM;
> +
> + /* vIRQ0-15 (SGIs) are reserved */
> + for (i = 0; i <= 15; i++)
> + set_bit(i, d->arch.vgic.allocated_irqs);
> +
> return 0;
> }
>
> @@ -119,6 +130,7 @@ void domain_vgic_free(struct domain *d)
> {
> xfree(d->arch.vgic.shared_irqs);
> xfree(d->arch.vgic.pending_irqs);
> + xfree(d->arch.vgic.allocated_irqs);
> }
>
> int vcpu_vgic_init(struct vcpu *v)
> @@ -441,6 +453,70 @@ int vgic_emulate(struct cpu_user_regs *regs, union hsr
> hsr)
> return v->domain->arch.vgic.handler->emulate_sysreg(regs, hsr);
> }
>
> +bool_t vgic_reserve_virq(struct domain *d, unsigned int virq)
> +{
> + bool_t reserved;
> +
> + if ( virq >= vgic_num_irqs(d) )
> + return 0;
> +
> + spin_lock(&d->arch.vgic.lock);
> + reserved = !test_and_set_bit(virq, d->arch.vgic.allocated_irqs);
> + spin_unlock(&d->arch.vgic.lock);
test_and_set_bit is atomic, why do you need to take the lock?
> + return reserved;
> +}
> +
> +int vgic_allocate_virq(struct domain *d, bool_t spi)
> +{
> + int ret = -1;
> + unsigned int virq;
> +
> + spin_lock(&d->arch.vgic.lock);
> + if ( !spi )
> + {
> + virq = find_first_zero_bit(d->arch.vgic.allocated_irqs, 32);
> + if ( virq >= 32 )
> + goto unlock;
> + }
> + else
> + {
> + virq = find_next_zero_bit(d->arch.vgic.allocated_irqs,
> + 32, vgic_num_irqs(d));
> + if ( virq >= vgic_num_irqs(d) )
> + goto unlock;
> + }
> +
> + set_bit(virq, d->arch.vgic.allocated_irqs);
> + ret = virq;
> +
> +unlock:
> + spin_unlock(&d->arch.vgic.lock);
you might be able to write this function without taking the lock too, by
using test_and_set_bit and retries:
retry:
virq = find_first_zero_bit;
if (test_and_set_bit(virq))
goto retry;
> + return ret;
> +}
> +
> +void vgic_free_virq(struct domain *d, unsigned int virq)
> +{
> + unsigned int spi;
> +
> + if ( is_hardware_domain(d) )
> + return;
> +
> + if ( virq < 32 && virq >= vgic_num_irqs(d) )
> + return;
> +
> + spi = virq - 32;
> +
> + /* Taking the vGIC domain lock is not necessary. We don't care if
> + * the bit is cleared a bit later. What only matters is bit to 1.
> + *
> + * With this solution vgic_allocate may fail to find an vIRQ if the
> + * allocated_irqs is fully. But we don't care.
> + */
> + clear_bit(spi, d->arch.vgic.allocated_irqs);
> +}
> +
> /*
> * Local variables:
> * mode: C
> diff --git a/xen/arch/arm/vtimer.c b/xen/arch/arm/vtimer.c
> index 2e95ceb..de660bb 100644
> --- a/xen/arch/arm/vtimer.c
> +++ b/xen/arch/arm/vtimer.c
> @@ -49,6 +49,21 @@ int domain_vtimer_init(struct domain *d)
> {
> d->arch.phys_timer_base.offset = NOW();
> d->arch.virt_timer_base.offset = READ_SYSREG64(CNTPCT_EL0);
> +
> + /* At this stage vgic_reserve_virq can't fail */
> + if ( is_hardware_domain(d) )
> + {
> + BUG_ON(!vgic_reserve_virq(d, timer_get_irq(TIMER_PHYS_SECURE_PPI)));
> + BUG_ON(!vgic_reserve_virq(d,
> timer_get_irq(TIMER_PHYS_NONSECURE_PPI)));
> + BUG_ON(!vgic_reserve_virq(d, timer_get_irq(TIMER_VIRT_PPI)));
> + }
> + else
> + {
> + BUG_ON(!vgic_reserve_virq(d, GUEST_TIMER_PHYS_S_PPI));
> + BUG_ON(!vgic_reserve_virq(d, GUEST_TIMER_PHYS_NS_PPI));
> + BUG_ON(!vgic_reserve_virq(d, GUEST_TIMER_VIRT_PPI));
> + }
> +
> return 0;
> }
>
> diff --git a/xen/include/asm-arm/domain.h b/xen/include/asm-arm/domain.h
> index 8b7dd85..d302fc9 100644
> --- a/xen/include/asm-arm/domain.h
> +++ b/xen/include/asm-arm/domain.h
> @@ -90,6 +90,7 @@ struct arch_domain
> spinlock_t lock;
> int ctlr;
> int nr_spis; /* Number of SPIs */
> + unsigned long *allocated_irqs; /* bitmap of IRQs allocated */
> struct vgic_irq_rank *shared_irqs;
> /*
> * SPIs are domain global, SGIs and PPIs are per-VCPU and stored in
> diff --git a/xen/include/asm-arm/vgic.h b/xen/include/asm-arm/vgic.h
> index 74d5a4e..9e167fa 100644
> --- a/xen/include/asm-arm/vgic.h
> +++ b/xen/include/asm-arm/vgic.h
> @@ -199,6 +199,19 @@ extern int vgic_to_sgi(struct vcpu *v, register_t sgir,
> enum gic_sgi_mode irqmode, int virq,
> unsigned long vcpu_mask);
> extern void vgic_migrate_irq(struct vcpu *old, struct vcpu *new, unsigned
> int irq);
> +
> +/* Reserve a specific guest vIRQ */
> +extern bool_t vgic_reserve_virq(struct domain *d, unsigned int virq);
> +
> +/*
> + * Allocate a guest VIRQ
> + * - spi == 0 => allocate a PPI. It will be the same on every vCPU
> + * - spi == 0 => allocate an SGI
> + */
> +extern int vgic_allocate_virq(struct domain *d, bool_t spi);
> +
> +extern void vgic_free_virq(struct domain *d, unsigned int irq);
> +
> #endif /* __ASM_ARM_VGIC_H__ */
>
> /*
> --
> 2.1.3
>
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |