From mboxrd@z Thu Jan 1 00:00:00 1970 From: Stefano Stabellini Subject: Re: [PATCH v4 12/17] xen/arm: ITS: Initialize LPI irq descriptors and route Date: Mon, 13 Jul 2015 18:03:39 +0100 Message-ID: References: <1436514172-3263-1-git-send-email-vijay.kilari@gmail.com> <1436514172-3263-13-git-send-email-vijay.kilari@gmail.com> Mime-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Return-path: In-Reply-To: <1436514172-3263-13-git-send-email-vijay.kilari@gmail.com> List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Sender: xen-devel-bounces@lists.xen.org Errors-To: xen-devel-bounces@lists.xen.org To: vijay.kilari@gmail.com Cc: Ian.Campbell@citrix.com, stefano.stabellini@eu.citrix.com, Prasun.Kapoor@caviumnetworks.com, Vijaya Kumar K , tim@xen.org, xen-devel@lists.xen.org, julien.grall@citrix.com, stefano.stabellini@citrix.com, manish.jaggi@caviumnetworks.com List-Id: xen-devel@lists.xenproject.org On Fri, 10 Jul 2015, vijay.kilari@gmail.com wrote: > From: Vijaya Kumar K > > Allocate and initialize irq descriptor for LPIs and > route LPIs to guest > > Signed-off-by: Vijaya Kumar K > --- > v4: - Merge patch #16 > - Changed commit message > --- > xen/arch/arm/gic-v3.c | 2 +- > xen/arch/arm/gic.c | 24 +++++++-- > xen/arch/arm/irq.c | 44 +++++++++++++---- > xen/arch/arm/vgic-v3-its.c | 9 ++++ > xen/arch/arm/vgic-v3.c | 15 ++++-- > xen/arch/arm/vgic.c | 110 ++++++++++++++++++++++++++++++++++++++--- > xen/include/asm-arm/domain.h | 3 ++ > xen/include/asm-arm/gic-its.h | 1 + > xen/include/asm-arm/gic.h | 7 ++- > xen/include/asm-arm/vgic.h | 1 + > 10 files changed, 192 insertions(+), 24 deletions(-) > > diff --git a/xen/arch/arm/gic-v3.c b/xen/arch/arm/gic-v3.c > index e6004d2..53554e6 100644 > --- a/xen/arch/arm/gic-v3.c > +++ b/xen/arch/arm/gic-v3.c > @@ -895,7 +895,7 @@ static void gicv3_update_lr(int lr, const struct pending_irq *p, > val |= ((uint64_t)p->priority & 0xff) << GICH_LR_PRIORITY_SHIFT; > val |= ((uint64_t)p->irq & GICH_LR_VIRTUAL_MASK) << GICH_LR_VIRTUAL_SHIFT; > > - if ( p->desc != NULL ) > + if ( p->desc != NULL && !(is_lpi(p->irq)) ) > val |= GICH_LR_HW | (((uint64_t)p->desc->irq & GICH_LR_PHYSICAL_MASK) > << GICH_LR_PHYSICAL_SHIFT); > > diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c > index 3ebadcf..92d2be9 100644 > --- a/xen/arch/arm/gic.c > +++ b/xen/arch/arm/gic.c > @@ -68,11 +68,18 @@ enum gic_version gic_hw_version(void) > return gic_hw_ops->info->hw_version; > } > > +/* Only validates PPIs/SGIs/SPIs supported */ > unsigned int gic_number_lines(void) > { > return gic_hw_ops->info->nr_lines; > } > > +/* Validates PPIs/SGIs/SPIs/LPIs supported */ > +bool_t gic_is_valid_irq(unsigned int irq) > +{ > + return ((irq < gic_hw_ops->info->nr_lines) && is_lpi(irq)); > +} shouldn't it be ((irq < gic_hw_ops->info->nr_lines) || is_lpi(irq)) ? > unsigned int gic_nr_id_bits(void) > { > return gic_hw_ops->info->nr_id_bits; > @@ -148,7 +155,7 @@ void gic_route_irq_to_xen(struct irq_desc *desc, const cpumask_t *cpu_mask, > { > ASSERT(priority <= 0xff); /* Only 8 bits of priority */ > /* Can't route interrupts that don't exist */ > - ASSERT(desc->irq < gic_number_lines() || is_lpi(desc->irq)); > + ASSERT(gic_is_valid_irq(desc->irq)); > ASSERT(test_bit(_IRQ_DISABLED, &desc->status)); > ASSERT(spin_is_locked(&desc->lock)); > > @@ -160,6 +167,17 @@ void gic_route_irq_to_xen(struct irq_desc *desc, const cpumask_t *cpu_mask, > /* Program the GIC to route an interrupt to a guest > * - desc.lock must be held > */ > +int gic_route_lpi_to_guest(struct domain *d, unsigned int virq, > + struct irq_desc *desc, unsigned int priority) > +{ > + ASSERT(spin_is_locked(&desc->lock)); > + > + desc->handler = get_guest_hw_irq_controller(desc->irq); > + set_bit(_IRQ_GUEST, &desc->status); > + > + return 0; > +} > + > int gic_route_irq_to_guest(struct domain *d, unsigned int virq, > struct irq_desc *desc, unsigned int priority) > { > @@ -454,7 +472,7 @@ static void gic_update_one_lr(struct vcpu *v, int i) > if ( test_bit(GIC_IRQ_GUEST_ENABLED, &p->status) && > test_and_clear_bit(GIC_IRQ_GUEST_QUEUED, &p->status) ) > { > - if ( p->desc == NULL ) > + if ( p->desc == NULL || is_lpi(irq) ) > { > lr_val.state |= GICH_LR_PENDING; > gic_hw_ops->write_lr(i, &lr_val); > @@ -677,7 +695,7 @@ void gic_interrupt(struct cpu_user_regs *regs, int is_fiq) > /* Reading IRQ will ACK it */ > irq = gic_hw_ops->read_irq(); > > - if ( likely(irq >= 16 && irq < 1020) ) > + if ( (likely(irq >= 16 && irq < 1020)) || is_lpi(irq) ) > { > local_irq_enable(); > do_IRQ(regs, irq, is_fiq); > diff --git a/xen/arch/arm/irq.c b/xen/arch/arm/irq.c > index 3806d98..c8ea627 100644 > --- a/xen/arch/arm/irq.c > +++ b/xen/arch/arm/irq.c > @@ -62,12 +62,21 @@ hw_irq_controller no_irq_type = { > }; > > static irq_desc_t irq_desc[NR_IRQS]; > +#ifdef CONFIG_ARM_64 > +static irq_desc_t irq_desc_lpi[NR_GIC_LPI]; > +#endif > static DEFINE_PER_CPU(irq_desc_t[NR_LOCAL_IRQS], local_irq_desc); > > irq_desc_t *__irq_to_desc(int irq) > { > if (irq < NR_LOCAL_IRQS) return &this_cpu(local_irq_desc)[irq]; > - return &irq_desc[irq-NR_LOCAL_IRQS]; > + else if ( irq >= NR_LOCAL_IRQS && irq < NR_IRQS) > + return &irq_desc[irq-NR_LOCAL_IRQS]; > +#ifdef CONFIG_ARM_64 > + else if ( is_lpi(irq) ) > + return &irq_desc_lpi[irq - NR_GIC_LPI]; > +#endif > + return NULL; > } > > int __init arch_init_one_irq_desc(struct irq_desc *desc) > @@ -88,6 +97,15 @@ static int __init init_irq_data(void) > desc->action = NULL; > } > > +#ifdef CONFIG_ARM_64 > + for ( irq = NR_GIC_LPI; irq < MAX_LPI; irq++ ) > + { > + struct irq_desc *desc = irq_to_desc(irq); > + init_one_irq_desc(desc); > + desc->irq = irq; > + desc->action = NULL; > + } > +#endif > return 0; > } > > @@ -208,7 +226,7 @@ int request_irq(unsigned int irq, unsigned int irqflags, > * which interrupt is which (messes up the interrupt freeing > * logic etc). > */ > - if ( irq >= nr_irqs ) > + if ( irq >= nr_irqs && !is_lpi(irq) ) > return -EINVAL; > if ( !handler ) > return -EINVAL; > @@ -267,9 +285,14 @@ void do_IRQ(struct cpu_user_regs *regs, unsigned int irq, int is_fiq) > set_bit(_IRQ_INPROGRESS, &desc->status); > desc->arch.eoi_cpu = smp_processor_id(); > > +#ifdef CONFIG_ARM_64 > + if ( is_lpi(irq) ) > + vgic_vcpu_inject_lpi(info->d, irq); > + else > +#endif > /* the irq cannot be a PPI, we only support delivery of SPIs to > * guests */ > - vgic_vcpu_inject_spi(info->d, info->virq); > + vgic_vcpu_inject_spi(info->d, info->virq); > goto out_no_end; > } > > @@ -436,7 +459,8 @@ err: > bool_t is_assignable_irq(unsigned int irq) > { > /* For now, we can only route SPIs to the guest */ > - return ((irq >= NR_LOCAL_IRQS) && (irq < gic_number_lines())); > + return (((irq >= NR_LOCAL_IRQS) && (irq < gic_number_lines())) || > + is_lpi(irq)); > } > > /* > @@ -452,7 +476,7 @@ int route_irq_to_guest(struct domain *d, unsigned int virq, > unsigned long flags; > int retval = 0; > > - if ( virq >= vgic_num_irqs(d) ) > + if ( virq >= vgic_num_irqs(d) && !is_lpi(irq) ) > { > printk(XENLOG_G_ERR > "the vIRQ number %u is too high for domain %u (max = %u)\n", > @@ -460,10 +484,10 @@ int route_irq_to_guest(struct domain *d, unsigned int virq, > return -EINVAL; > } > > - /* Only routing to virtual SPIs is supported */ > + /* Only routing to virtual SPIs/LPIs is supported */ > if ( virq < NR_LOCAL_IRQS ) > { > - printk(XENLOG_G_ERR "IRQ can only be routed to an SPI\n"); > + printk(XENLOG_G_ERR "IRQ can only be routed to an SPI/LPI\n"); > return -EINVAL; > } > > @@ -537,8 +561,10 @@ int route_irq_to_guest(struct domain *d, unsigned int virq, > retval = __setup_irq(desc, 0, action); > if ( retval ) > goto out; > - > - retval = gic_route_irq_to_guest(d, virq, desc, GIC_PRI_IRQ); > + if ( is_lpi(irq) ) > + retval = gic_route_lpi_to_guest(d, virq, desc, GIC_PRI_IRQ); > + else > + retval = gic_route_irq_to_guest(d, virq, desc, GIC_PRI_IRQ); > > spin_unlock_irqrestore(&desc->lock, flags); > > diff --git a/xen/arch/arm/vgic-v3-its.c b/xen/arch/arm/vgic-v3-its.c > index bbcc7bb..4649b07 100644 > --- a/xen/arch/arm/vgic-v3-its.c > +++ b/xen/arch/arm/vgic-v3-its.c > @@ -625,6 +625,15 @@ err: > return 0; > } > > +uint8_t vgic_its_get_priority(struct vcpu *v, uint32_t pid) > +{ > + uint8_t priority; > + > + priority = readb_relaxed(v->domain->arch.vits->prop_page + pid); > + priority &= LPI_PRIORITY_MASK; > + > + return priority; > +} > static int vgic_v3_gits_lpi_mmio_read(struct vcpu *v, mmio_info_t *info) > { > uint32_t offset; > diff --git a/xen/arch/arm/vgic-v3.c b/xen/arch/arm/vgic-v3.c > index 25b69a0..4e14439 100644 > --- a/xen/arch/arm/vgic-v3.c > +++ b/xen/arch/arm/vgic-v3.c > @@ -1111,12 +1111,19 @@ static const struct mmio_handler_ops vgic_distr_mmio_handler = { > > static int vgic_v3_get_irq_priority(struct vcpu *v, unsigned int irq) > { > - int priority; > - struct vgic_irq_rank *rank = vgic_rank_irq(v, irq); > + int priority = 0; > + struct vgic_irq_rank *rank; > > - ASSERT(spin_is_locked(&rank->lock)); > - priority = vgic_byte_read(rank->ipriority[REG_RANK_INDEX(8, > + if ( !is_lpi(irq) ) > + { > + rank = vgic_rank_irq(v, irq); > + > + ASSERT(spin_is_locked(&rank->lock)); > + priority = vgic_byte_read(rank->ipriority[REG_RANK_INDEX(8, > irq, DABT_WORD)], 0, irq & 0x3); > + } > + if ( is_lpi(irq) && gic_lpi_supported() ) > + priority = vgic_its_get_priority(v, irq); > > return priority; > } > diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c > index a5f66f6..8190a46 100644 > --- a/xen/arch/arm/vgic.c > +++ b/xen/arch/arm/vgic.c > @@ -30,6 +30,7 @@ > > #include > #include > +#include > #include > > static inline struct vgic_irq_rank *vgic_get_rank(struct vcpu *v, int rank) > @@ -111,6 +112,15 @@ int domain_vgic_init(struct domain *d, unsigned int nr_spis) > for (i=0; iarch.vgic.nr_spis; i++) > vgic_init_pending_irq(&d->arch.vgic.pending_irqs[i], i + 32); > > +#ifdef CONFIG_ARM_64 > + d->arch.vgic.pending_lpis = xzalloc_array(struct pending_irq, NR_GIC_LPI); > + if ( d->arch.vgic.pending_lpis == NULL ) > + return -ENOMEM; > + > + for ( i = 0; i < NR_GIC_LPI; i++ ) > + vgic_init_pending_irq(&d->arch.vgic.pending_lpis[i], i); > +#endif > + > for (i=0; i spin_lock_init(&d->arch.vgic.shared_irqs[i].lock); > > @@ -157,6 +167,7 @@ void domain_vgic_free(struct domain *d) > #ifdef CONFIG_ARM_64 > free_xenheap_pages(d->arch.vits->prop_page, > get_order_from_bytes(d->arch.vits->prop_size)); > + xfree(d->arch.vgic.pending_lpis); > #endif > } > > @@ -381,13 +392,17 @@ int vgic_to_sgi(struct vcpu *v, register_t sgir, enum gic_sgi_mode irqmode, int > > struct pending_irq *irq_to_pending(struct vcpu *v, unsigned int irq) > { > - struct pending_irq *n; > + struct pending_irq *n = NULL; > /* 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 > + else if ( irq < NR_IRQS ) > n = &v->domain->arch.vgic.pending_irqs[irq - 32]; > +#ifdef CONFIG_ARM_64 > + else if ( is_lpi(irq) ) > + n = &v->domain->arch.vgic.pending_lpis[irq - FIRST_GIC_LPI]; > +#endif > return n; > } > > @@ -413,14 +428,20 @@ void vgic_clear_pending_irqs(struct vcpu *v) > void vgic_vcpu_inject_irq(struct vcpu *v, unsigned int virq) > { > uint8_t priority; > - struct vgic_irq_rank *rank = vgic_rank_irq(v, virq); > + struct vgic_irq_rank *rank; > struct pending_irq *iter, *n = irq_to_pending(v, virq); > unsigned long flags; > bool_t running; > > - vgic_lock_rank(v, rank, flags); > - priority = v->domain->arch.vgic.handler->get_irq_priority(v, virq); > - vgic_unlock_rank(v, rank, flags); > + if ( virq < NR_GIC_LPI ) > + { > + rank = vgic_rank_irq(v, virq); > + vgic_lock_rank(v, rank, flags); > + priority = v->domain->arch.vgic.handler->get_irq_priority(v, virq); > + vgic_unlock_rank(v, rank, flags); > + } > + else > + priority = v->domain->arch.vgic.handler->get_irq_priority(v, virq); > > spin_lock_irqsave(&v->arch.vgic.lock, flags); >