[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [PATCH 08/10] xen/arm: vgic: add resource management for extended SPIs
This change introduces resource management in the VGIC to handle extended SPIs introduced in GICv3.1. The pending_irqs and allocated_irqs arrays are resized to support the required number of eSPIs, based on what is supported by the hardware and requested by the guest. A new field, ext_shared_irqs, is added to the VGIC structure to store information about eSPIs, similar to how shared_irqs is used for regular SPIs. Since the eSPI range starts at INTID 4096 and INTIDs between 1025 and 4095 are reserved, helper macros are introduced to simplify the transformation of indices and to enable easier access to eSPI-specific resources. These changes prepare the VGIC for processing eSPIs as required by future functionality. The initialization and deinitialization paths for vgic have been updated to allocate and free these resources appropriately. Additionally, updated handling of INTIDs greater than 1024, passed from the toolstack during domain creation, and verification logic ensures only valid SPI or eSPI INTIDs are used. The existing SPI behavior remains unaffected when guests do not request eSPIs, GIC hardware does not support them, or the CONFIG_GICV3_ESPI option is disabled. Signed-off-by: Leonid Komarianskyi <leonid_komarianskyi@xxxxxxxx> --- xen/arch/arm/gic-v3.c | 5 ++ xen/arch/arm/include/asm/gic.h | 3 + xen/arch/arm/include/asm/vgic.h | 28 +++++++ xen/arch/arm/vgic.c | 133 +++++++++++++++++++++++++++++++- 4 files changed, 167 insertions(+), 2 deletions(-) diff --git a/xen/arch/arm/gic-v3.c b/xen/arch/arm/gic-v3.c index 476524225d..a0e8ee1a1e 100644 --- a/xen/arch/arm/gic-v3.c +++ b/xen/arch/arm/gic-v3.c @@ -676,6 +676,11 @@ static void gicv3_set_irq_priority(struct irq_desc *desc, } #ifdef CONFIG_GICV3_ESPI +unsigned int gic_number_espis(void) +{ + return gic_hw_ops->info->nr_espi; +} + static void gicv3_dist_espi_common_init(uint32_t type) { unsigned int espi_nr; diff --git a/xen/arch/arm/include/asm/gic.h b/xen/arch/arm/include/asm/gic.h index 1c4e3cf31e..64baafb902 100644 --- a/xen/arch/arm/include/asm/gic.h +++ b/xen/arch/arm/include/asm/gic.h @@ -306,6 +306,9 @@ extern void gic_dump_vgic_info(struct vcpu *v); /* Number of interrupt lines */ extern unsigned int gic_number_lines(void); +#ifdef CONFIG_GICV3_ESPI +extern unsigned int gic_number_espis(void); +#endif /* IRQ translation function for the device tree */ int gic_irq_xlate(const u32 *intspec, unsigned int intsize, diff --git a/xen/arch/arm/include/asm/vgic.h b/xen/arch/arm/include/asm/vgic.h index 35c0c6a8b0..3731750046 100644 --- a/xen/arch/arm/include/asm/vgic.h +++ b/xen/arch/arm/include/asm/vgic.h @@ -146,6 +146,10 @@ struct vgic_dist { int nr_spis; /* Number of SPIs */ unsigned long *allocated_irqs; /* bitmap of IRQs allocated */ struct vgic_irq_rank *shared_irqs; +#ifdef CONFIG_GICV3_ESPI + struct vgic_irq_rank *ext_shared_irqs; + int nr_espis; /* Number of extended SPIs */ +#endif /* * SPIs are domain global, SGIs and PPIs are per-VCPU and stored in * struct arch_vcpu. @@ -243,6 +247,24 @@ struct vgic_ops { /* Number of ranks of interrupt registers for a domain */ #define DOMAIN_NR_RANKS(d) (((d)->arch.vgic.nr_spis+31)/32) +#ifdef CONFIG_GICV3_ESPI +#define DOMAIN_NR_EXT_RANKS(d) (((d)->arch.vgic.nr_espis+31)/32) +#define EXT_RANK_MIN (ESPI_BASE_INTID/32) +#define EXT_RANK_MAX ((ESPI_MAX_INTID+31)/32) +#define EXT_RANK_NUM2IDX(num) ((num)-EXT_RANK_MIN) +#define EXT_RANK_IDX2NUM(idx) ((idx)+EXT_RANK_MIN) + +/* + * Since eSPI indexes start from 4096 and numbers from 1024 to + * 4095 are forbidden, we need to check both lower and upper + * limits for ranks. + */ +static inline bool is_espi_rank(unsigned int rank) +{ + return ( rank >= EXT_RANK_MIN && rank < EXT_RANK_MAX ); +} +#endif + #define vgic_lock(v) spin_lock_irq(&(v)->domain->arch.vgic.lock) #define vgic_unlock(v) spin_unlock_irq(&(v)->domain->arch.vgic.lock) @@ -302,6 +324,12 @@ extern struct vgic_irq_rank *vgic_rank_offset(struct vcpu *v, unsigned int b, unsigned int n, unsigned int s); +#ifdef CONFIG_GICV3_ESPI +extern struct vgic_irq_rank *vgic_ext_rank_offset(struct vcpu *v, + unsigned int b, + unsigned int n, + unsigned int s); +#endif extern struct vgic_irq_rank *vgic_rank_irq(struct vcpu *v, unsigned int irq); extern void vgic_disable_irqs(struct vcpu *v, uint32_t r, unsigned int n); extern void vgic_enable_irqs(struct vcpu *v, uint32_t r, unsigned int n); diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c index c563ba93af..8b3bbdf918 100644 --- a/xen/arch/arm/vgic.c +++ b/xen/arch/arm/vgic.c @@ -31,6 +31,10 @@ static inline struct vgic_irq_rank *vgic_get_rank(struct vcpu *v, return v->arch.vgic.private_irqs; else if ( rank <= DOMAIN_NR_RANKS(v->domain) ) return &v->domain->arch.vgic.shared_irqs[rank - 1]; +#ifdef CONFIG_GICV3_ESPI + else if ( is_espi_rank(rank) ) + return &v->domain->arch.vgic.ext_shared_irqs[EXT_RANK_NUM2IDX(rank)]; +#endif else return NULL; } @@ -47,6 +51,16 @@ struct vgic_irq_rank *vgic_rank_offset(struct vcpu *v, unsigned int b, return vgic_get_rank(v, rank); } +#ifdef CONFIG_GICV3_ESPI +struct vgic_irq_rank *vgic_ext_rank_offset(struct vcpu *v, unsigned int b, + unsigned int n, unsigned int s) +{ + unsigned int rank = REG_RANK_NR(b, (n >> s)); + + return vgic_get_rank(v, rank + EXT_RANK_MIN); +} +#endif + struct vgic_irq_rank *vgic_rank_irq(struct vcpu *v, unsigned int irq) { unsigned int rank = irq / 32; @@ -111,6 +125,29 @@ int domain_vgic_register(struct domain *d, unsigned int *mmio_count) return 0; } +#ifdef CONFIG_GICV3_ESPI +static int init_vgic_espi(struct domain *d) +{ + int i; + + if ( d->arch.vgic.nr_espis == 0 ) + return 0; + + d->arch.vgic.ext_shared_irqs = + xzalloc_array(struct vgic_irq_rank, DOMAIN_NR_EXT_RANKS(d)); + if ( d->arch.vgic.ext_shared_irqs == NULL ) + return -ENOMEM; + + for ( i = 0; i < d->arch.vgic.nr_espis; i++ ) + vgic_init_pending_irq(&d->arch.vgic.pending_irqs[i + d->arch.vgic.nr_spis], ESPI_IDX2INTID(i)); + + for ( i = 0; i < DOMAIN_NR_EXT_RANKS(d); i++ ) + vgic_rank_init(&d->arch.vgic.ext_shared_irqs[i], i, 0); + + return 0; +} +#endif + int domain_vgic_init(struct domain *d, unsigned int nr_spis) { int i; @@ -125,6 +162,30 @@ int domain_vgic_init(struct domain *d, unsigned int nr_spis) */ nr_spis = ROUNDUP(nr_spis, 32); +#ifdef CONFIG_GICV3_ESPI + if ( nr_spis > ESPI_MAX_INTID ) + return -EINVAL; + + if ( is_espi(nr_spis) ) + { + /* + * During domain creation, the toolstack specifies the maximum INTID, + * which is defined in the domain config subtracted by 32. To compute the + * actual number of eSPI that will be usable for, add back 32. + */ + d->arch.vgic.nr_espis = min(nr_spis - ESPI_BASE_INTID + 32, 1024U); + /* Verify if GIC HW can handle provided INTID */ + if ( d->arch.vgic.nr_espis > gic_number_espis() ) + return -EINVAL; + /* Set the maximum available number for defult SPI to pass the next check */ + nr_spis = VGIC_DEF_NR_SPIS; + } else + { + /* Domain will use the regular SPI range */ + d->arch.vgic.nr_espis = 0; + } +#endif + /* Limit the number of virtual SPIs supported to (1020 - 32) = 988 */ if ( nr_spis > (1020 - NR_LOCAL_IRQS) ) return -EINVAL; @@ -139,7 +200,12 @@ int domain_vgic_init(struct domain *d, unsigned int nr_spis) return -ENOMEM; d->arch.vgic.pending_irqs = +#ifdef CONFIG_GICV3_ESPI + xzalloc_array(struct pending_irq, d->arch.vgic.nr_spis + + d->arch.vgic.nr_espis); +#else xzalloc_array(struct pending_irq, d->arch.vgic.nr_spis); +#endif if ( d->arch.vgic.pending_irqs == NULL ) return -ENOMEM; @@ -150,12 +216,23 @@ int domain_vgic_init(struct domain *d, unsigned int nr_spis) for ( i = 0; i < DOMAIN_NR_RANKS(d); i++ ) vgic_rank_init(&d->arch.vgic.shared_irqs[i], i + 1, 0); +#ifdef CONFIG_GICV3_ESPI + ret = init_vgic_espi(d); + if ( ret ) + return ret; +#endif + ret = d->arch.vgic.handler->domain_init(d); if ( ret ) return ret; d->arch.vgic.allocated_irqs = +#ifdef CONFIG_GICV3_ESPI + xzalloc_array(unsigned long, BITS_TO_LONGS(vgic_num_irqs(d) + + d->arch.vgic.nr_espis)); +#else xzalloc_array(unsigned long, BITS_TO_LONGS(vgic_num_irqs(d))); +#endif if ( !d->arch.vgic.allocated_irqs ) return -ENOMEM; @@ -189,9 +266,27 @@ void domain_vgic_free(struct domain *d) } } +#ifdef CONFIG_GICV3_ESPI + for ( i = 0; i < (d->arch.vgic.nr_espis); i++ ) + { + struct pending_irq *p = spi_to_pending(d, ESPI_IDX2INTID(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); + } + } +#endif + if ( d->arch.vgic.handler ) d->arch.vgic.handler->domain_free(d); xfree(d->arch.vgic.shared_irqs); +#ifdef CONFIG_GICV3_ESPI + xfree(d->arch.vgic.ext_shared_irqs); +#endif xfree(d->arch.vgic.pending_irqs); xfree(d->arch.vgic.allocated_irqs); } @@ -325,6 +420,17 @@ void arch_move_irqs(struct vcpu *v) if ( v_target == v && !test_bit(GIC_IRQ_GUEST_MIGRATING, &p->status) ) irq_set_affinity(p->desc, cpu_mask); } + +#ifdef CONFIG_GICV3_ESPI + for ( i = ESPI_BASE_INTID; i < (d)->arch.vgic.nr_espis; i++ ) + { + v_target = vgic_get_target_vcpu(v, i); + p = irq_to_pending(v_target, i); + + if ( v_target == v && !test_bit(GIC_IRQ_GUEST_MIGRATING, &p->status) ) + irq_set_affinity(p->desc, cpu_mask); + } +#endif } void vgic_disable_irqs(struct vcpu *v, uint32_t r, unsigned int n) @@ -532,6 +638,10 @@ struct pending_irq *irq_to_pending(struct vcpu *v, unsigned int irq) n = &v->arch.vgic.pending_irqs[irq]; else if ( is_lpi(irq) ) n = v->domain->arch.vgic.handler->lpi_to_pending(v->domain, irq); +#ifdef CONFIG_GICV3_ESPI + else if ( is_espi(irq) ) + n = &v->domain->arch.vgic.pending_irqs[ESPI_INTID2IDX(irq) + v->domain->arch.vgic.nr_spis]; +#endif else n = &v->domain->arch.vgic.pending_irqs[irq - 32]; return n; @@ -541,6 +651,14 @@ struct pending_irq *spi_to_pending(struct domain *d, unsigned int irq) { ASSERT(irq >= NR_LOCAL_IRQS); +#ifdef CONFIG_GICV3_ESPI + if ( is_espi(irq) ) + { + irq = ESPI_INTID2IDX(irq) + d->arch.vgic.nr_spis; + return &d->arch.vgic.pending_irqs[irq]; + } +#endif + return &d->arch.vgic.pending_irqs[irq - 32]; } @@ -582,7 +700,7 @@ void vgic_inject_irq(struct domain *d, struct vcpu *v, unsigned int virq, if ( !v ) { /* The IRQ needs to be an SPI if no vCPU is specified. */ - ASSERT(virq >= 32 && virq <= vgic_num_irqs(d)); + ASSERT((virq >= 32 && virq <= vgic_num_irqs(d)) || is_espi(virq)); v = vgic_get_target_vcpu(d->vcpu[0], virq); }; @@ -659,9 +777,14 @@ bool vgic_emulate(struct cpu_user_regs *regs, union hsr hsr) bool vgic_reserve_virq(struct domain *d, unsigned int virq) { - if ( virq >= vgic_num_irqs(d) ) + if ( virq >= vgic_num_irqs(d) && !is_espi(virq) ) return false; +#ifdef CONFIG_GICV3_ESPI + if ( is_espi(virq) ) + return !test_and_set_bit(ESPI_INTID2IDX(virq) + vgic_num_irqs(d), d->arch.vgic.allocated_irqs); +#endif + return !test_and_set_bit(virq, d->arch.vgic.allocated_irqs); } @@ -679,7 +802,13 @@ int vgic_allocate_virq(struct domain *d, bool spi) else { first = 32; + end = vgic_num_irqs(d); +#ifdef CONFIG_GICV3_ESPI + /* Take into account extended SPI range */ + end += d->arch.vgic.nr_espis; +#endif + } /* -- 2.34.1
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |