[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [RFC PATCH 08/24] ARM: GICv3: introduce separate pending_irq structs for LPIs
On Wed, Sep 28, 2016 at 11:54 PM, Andre Przywara <andre.przywara@xxxxxxx> wrote: > For the same reason that allocating a struct irq_desc for each > possible LPI is not an option, having a struct pending_irq for each LPI > is also not feasible. However we actually only need those when an > interrupt is on a vCPU (or is about to be injected). > Maintain a list of those structs that we can use for the lifecycle of > a guest LPI. We allocate new entries if necessary, however reuse > pre-owned entries whenever possible. > Teach the existing VGIC functions to find the right pointer when being > given a virtual LPI number. > > Signed-off-by: Andre Przywara <andre.przywara@xxxxxxx> > --- > xen/arch/arm/gic.c | 3 +++ > xen/arch/arm/vgic-v3.c | 2 ++ > xen/arch/arm/vgic.c | 56 > ++++++++++++++++++++++++++++++++++++++++--- > xen/include/asm-arm/domain.h | 1 + > xen/include/asm-arm/gic-its.h | 10 ++++++++ > xen/include/asm-arm/vgic.h | 9 +++++++ > 6 files changed, 78 insertions(+), 3 deletions(-) > > diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c > index 63c744a..ebe4035 100644 > --- a/xen/arch/arm/gic.c > +++ b/xen/arch/arm/gic.c > @@ -506,6 +506,9 @@ static void gic_update_one_lr(struct vcpu *v, int i) > struct vcpu *v_target = vgic_get_target_vcpu(v, irq); > irq_set_affinity(p->desc, cpumask_of(v_target->processor)); > } > + /* If this was an LPI, mark this struct as available again. */ > + if ( p->irq >= 8192 ) Can define something line is_lpi(irq) and use it everywhere > + p->irq = 0; > } > } > } > diff --git a/xen/arch/arm/vgic-v3.c b/xen/arch/arm/vgic-v3.c > index ec038a3..e9b6490 100644 > --- a/xen/arch/arm/vgic-v3.c > +++ b/xen/arch/arm/vgic-v3.c > @@ -1388,6 +1388,8 @@ static int vgic_v3_vcpu_init(struct vcpu *v) > if ( v->vcpu_id == last_cpu || (v->vcpu_id == (d->max_vcpus - 1)) ) > v->arch.vgic.flags |= VGIC_V3_RDIST_LAST; > > + INIT_LIST_HEAD(&v->arch.vgic.pending_lpi_list); > + > return 0; > } > > diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c > index 0965119..b961551 100644 > --- a/xen/arch/arm/vgic.c > +++ b/xen/arch/arm/vgic.c > @@ -31,6 +31,8 @@ > #include <asm/mmio.h> > #include <asm/gic.h> > #include <asm/vgic.h> > +#include <asm/gic_v3_defs.h> > +#include <asm/gic-its.h> > > static inline struct vgic_irq_rank *vgic_get_rank(struct vcpu *v, int rank) > { > @@ -61,7 +63,7 @@ struct vgic_irq_rank *vgic_rank_irq(struct vcpu *v, > unsigned int irq) > return vgic_get_rank(v, rank); > } > > -static void vgic_init_pending_irq(struct pending_irq *p, unsigned int virq) > +void vgic_init_pending_irq(struct pending_irq *p, unsigned int virq) > { > INIT_LIST_HEAD(&p->inflight); > INIT_LIST_HEAD(&p->lr_queue); > @@ -244,10 +246,14 @@ struct vcpu *vgic_get_target_vcpu(struct vcpu *v, > unsigned int virq) > > static int vgic_get_virq_priority(struct vcpu *v, unsigned int virq) > { > - struct vgic_irq_rank *rank = vgic_rank_irq(v, virq); > + struct vgic_irq_rank *rank; > unsigned long flags; > int priority; > > + if ( virq >= 8192 ) > + return gicv3_lpi_get_priority(v->domain, virq); > + > + rank = vgic_rank_irq(v, virq); > vgic_lock_rank(v, rank, flags); > priority = rank->priority[virq & INTERRUPT_RANK_MASK]; > vgic_unlock_rank(v, rank, flags); > @@ -446,13 +452,55 @@ int vgic_to_sgi(struct vcpu *v, register_t sgir, enum > gic_sgi_mode irqmode, int > return 1; > } > > +/* > + * Holding struct pending_irq's for each possible virtual LPI in each domain > + * requires too much Xen memory, also a malicious guest could potentially > + * spam Xen with LPI map requests. We cannot cover those with (guest > allocated) > + * ITS memory, so we use a dynamic scheme of allocating struct pending_irq's > + * on demand. > + */ > +struct pending_irq *lpi_to_pending(struct vcpu *v, unsigned int lpi, > + bool allocate) > +{ > + struct lpi_pending_irq *lpi_irq, *empty = NULL; > + > + /* TODO: locking! */ > + list_for_each_entry(lpi_irq, &v->arch.vgic.pending_lpi_list, entry) > + { > + if ( lpi_irq->pirq.irq == lpi ) > + return &lpi_irq->pirq; > + > + if ( lpi_irq->pirq.irq == 0 && !empty ) > + empty = lpi_irq; > + } With this approach of allocating pending_irq on demand, if the pending_lpi_list is at n position then it iterates for long time to find pending_irq entry. This will increase LPI injection time to domain. Why can't we use btree? > + > + if ( !allocate ) > + return NULL; > + > + if ( !empty ) > + { > + empty = xzalloc(struct lpi_pending_irq); > + vgic_init_pending_irq(&empty->pirq, lpi); > + list_add_tail(&empty->entry, &v->arch.vgic.pending_lpi_list); > + } else > + { > + empty->pirq.status = 0; > + empty->pirq.irq = lpi; > + } > + > + return &empty->pirq; > +} > + > struct pending_irq *irq_to_pending(struct vcpu *v, unsigned int irq) > { > struct pending_irq *n; > + > /* Pending irqs allocation strategy: the first vgic.nr_spis irqs > * are used for SPIs; the rests are used for per cpu irqs */ > if ( irq < 32 ) > n = &v->arch.vgic.pending_irqs[irq]; > + else if ( irq >= 8192 ) > + n = lpi_to_pending(v, irq, true); > else > n = &v->domain->arch.vgic.pending_irqs[irq - 32]; > return n; > @@ -480,7 +528,7 @@ void vgic_clear_pending_irqs(struct vcpu *v) > void vgic_vcpu_inject_irq(struct vcpu *v, unsigned int virq) > { > uint8_t priority; > - struct pending_irq *iter, *n = irq_to_pending(v, virq); > + struct pending_irq *iter, *n; > unsigned long flags; > bool_t running; > > @@ -488,6 +536,8 @@ void vgic_vcpu_inject_irq(struct vcpu *v, unsigned int > virq) > > spin_lock_irqsave(&v->arch.vgic.lock, flags); > > + n = irq_to_pending(v, virq); > + > /* vcpu offline */ > if ( test_bit(_VPF_down, &v->pause_flags) ) > { > diff --git a/xen/include/asm-arm/domain.h b/xen/include/asm-arm/domain.h > index 9452fcd..ae8a9de 100644 > --- a/xen/include/asm-arm/domain.h > +++ b/xen/include/asm-arm/domain.h > @@ -249,6 +249,7 @@ struct arch_vcpu > paddr_t rdist_base; > #define VGIC_V3_RDIST_LAST (1 << 0) /* last vCPU of the rdist */ > uint8_t flags; > + struct list_head pending_lpi_list; > } vgic; > > /* Timer registers */ > diff --git a/xen/include/asm-arm/gic-its.h b/xen/include/asm-arm/gic-its.h > index 4e9841a..1f881c0 100644 > --- a/xen/include/asm-arm/gic-its.h > +++ b/xen/include/asm-arm/gic-its.h > @@ -136,6 +136,12 @@ int gicv3_lpi_allocate_host_lpi(struct host_its *its, > int gicv3_lpi_drop_host_lpi(struct host_its *its, > uint32_t devid, uint32_t eventid, > uint32_t host_lpi); > + > +static inline int gicv3_lpi_get_priority(struct domain *d, uint32_t lpi) > +{ > + return GIC_PRI_IRQ; Why lpi priority is fixed?. can't we use domain set lpi priority? > +} > + > #else > > static inline void gicv3_its_dt_init(const struct dt_device_node *node) > @@ -175,6 +181,10 @@ static inline int gicv3_lpi_drop_host_lpi(struct > host_its *its, > { > return 0; > } > +static inline int gicv3_lpi_get_priority(struct domain *d, uint32_t lpi) > +{ > + return GIC_PRI_IRQ; > +} > > #endif /* CONFIG_HAS_ITS */ > > diff --git a/xen/include/asm-arm/vgic.h b/xen/include/asm-arm/vgic.h > index 300f461..4e29ba6 100644 > --- a/xen/include/asm-arm/vgic.h > +++ b/xen/include/asm-arm/vgic.h > @@ -83,6 +83,12 @@ struct pending_irq > struct list_head lr_queue; > }; > > +struct lpi_pending_irq > +{ > + struct list_head entry; > + struct pending_irq pirq; > +}; > + > #define NR_INTERRUPT_PER_RANK 32 > #define INTERRUPT_RANK_MASK (NR_INTERRUPT_PER_RANK - 1) > > @@ -296,8 +302,11 @@ extern struct vcpu *vgic_get_target_vcpu(struct vcpu *v, > unsigned int virq); > extern void vgic_vcpu_inject_irq(struct vcpu *v, unsigned int virq); > extern void vgic_vcpu_inject_spi(struct domain *d, unsigned int virq); > extern void vgic_clear_pending_irqs(struct vcpu *v); > +extern void vgic_init_pending_irq(struct pending_irq *p, unsigned int virq); > extern struct pending_irq *irq_to_pending(struct vcpu *v, unsigned int irq); > extern struct pending_irq *spi_to_pending(struct domain *d, unsigned int > irq); > +extern struct pending_irq *lpi_to_pending(struct vcpu *v, unsigned int irq, > + bool allocate); > extern struct vgic_irq_rank *vgic_rank_offset(struct vcpu *v, int b, int n, > int s); > extern struct vgic_irq_rank *vgic_rank_irq(struct vcpu *v, unsigned int irq); > extern int vgic_emulate(struct cpu_user_regs *regs, union hsr hsr); > -- > 2.9.0 > > > _______________________________________________ > Xen-devel mailing list > Xen-devel@xxxxxxxxxxxxx > https://lists.xen.org/xen-devel _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx https://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |