[Xen-devel] [RFC PATCH 17/19] xen/arm: its: Support ITS interrupt handling
From: Vijaya Kumar K Add support for handling ITS(LPI) interrupts. The LPI interrupts are handled by physical ITS driver. nested LPI interrupt handling is not tested and enabled. Signed-off-by: Vijaya Kumar K --- xen/arch/arm/gic-v3-its.c | 31 +++ xen/arch/arm/gic-v3.c |8 ++-- xen/arch/arm/gic.c | 38 -- xen/arch/arm/irq.c | 10 +++--- xen/arch/arm/vgic-v3-its.c | 10 ++ xen/arch/arm/vgic.c| 14 ++ xen/include/asm-arm/gic.h |3 +++ xen/include/asm-arm/irq.h |1 + 8 files changed, 104 insertions(+), 11 deletions(-) diff --git a/xen/arch/arm/gic-v3-its.c b/xen/arch/arm/gic-v3-its.c index b2c3320..7adbee4 100644 --- a/xen/arch/arm/gic-v3-its.c +++ b/xen/arch/arm/gic-v3-its.c @@ -344,6 +344,37 @@ static const struct gic_its_hw_operations gic_its_ops = { .gic_guest_lpi_type = &gic_guest_its_type, }; +void its_handle_lpi(uint32_t irqnr, struct cpu_user_regs *regs) +{ +struct domain *d; +struct irq_desc *desc = irq_to_desc(irqnr); + +irq_enter(); +spin_lock(&desc->lock); + +if ( !desc->action ) +{ +printk("UNKNOWN LPI without handler\n"); +goto err; +} + +if ( desc->status & IRQ_GUEST ) +{ +d = irq_get_domain(desc); + +desc->handler->end(desc); + +desc->status |= IRQ_INPROGRESS; +desc->arch.eoi_cpu = smp_processor_id(); + +/* XXX: inject irq into all guest vcpus */ +vgic_vcpu_inject_irq(d->vcpu[0], irqnr); +} +err: +spin_unlock(&desc->lock); +irq_exit(); +} + static u64 its_cmd_ptr_to_offset(struct its_node *its, struct its_cmd_block *ptr) { diff --git a/xen/arch/arm/gic-v3.c b/xen/arch/arm/gic-v3.c index 02e71dd..b654535 100644 --- a/xen/arch/arm/gic-v3.c +++ b/xen/arch/arm/gic-v3.c @@ -848,9 +848,13 @@ static void gicv3_update_lr(int lr, const struct pending_irq *p, val = (((uint64_t)state & 0x3) << GICH_LR_STATE_SHIFT) | grp; 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 ( is_lpi(p->irq) ) +val |= ((uint64_t)p->desc->virq & GICH_LR_VIRTUAL_MASK) << GICH_LR_VIRTUAL_SHIFT; +else +val |= ((uint64_t)p->irq & GICH_LR_VIRTUAL_MASK) << GICH_LR_VIRTUAL_SHIFT; + + 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 fb77387..c4d352a 100644 --- a/xen/arch/arm/gic.c +++ b/xen/arch/arm/gic.c @@ -34,6 +34,7 @@ #include #include #include +#include static void gic_restore_pending_irqs(struct vcpu *v); @@ -134,6 +135,21 @@ void gic_route_irq_to_xen(struct irq_desc *desc, const cpumask_t *cpu_mask, gic_set_irq_properties(desc, cpu_mask, priority); } +void gic_route_lpi_to_guest(struct domain *d, struct irq_desc *desc, +const cpumask_t *cpu_mask, unsigned int priority) +{ +struct pending_irq *p; +ASSERT(spin_is_locked(&desc->lock)); + +desc->handler = gic_its_hw_ops->gic_guest_lpi_type; +set_bit(_IRQ_GUEST, &desc->status); + + +/* TODO: do not assume delivery to vcpu0 */ +p = irq_to_pending(d->vcpu[0], desc->irq); +p->desc = desc; +} + /* Program the GIC to route an interrupt to a guest * - desc.lock must be held */ @@ -341,20 +357,33 @@ static void gic_update_one_lr(struct vcpu *v, int i) struct pending_irq *p; int irq; struct gic_lr lr_val; +uint32_t pirq; ASSERT(spin_is_locked(&v->arch.vgic.lock)); ASSERT(!local_irq_is_enabled()); gic_hw_ops->read_lr(i, &lr_val); irq = lr_val.virq; -p = irq_to_pending(v, irq); + +if ( is_lpi(irq) ) +{ +// Fetch corresponding plpi for vlpi +if ( vgic_its_get_pid(v, irq, &pirq) ) +BUG(); +p = irq_to_pending(v, pirq); +irq = pirq; +} +else +{ +p = irq_to_pending(v, irq); +} if ( lr_val.state & GICH_LR_ACTIVE ) { set_bit(GIC_IRQ_GUEST_ACTIVE, &p->status); 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); @@ -580,6 +609,11 @@ void gic_interrupt(struct cpu_user_regs *regs, int is_fiq) do { /* Reading IRQ will ACK it */ irq = gic_hw_ops->read_irq(); +if ( is_lpi(irq) ) { +// TODO: Enable irqs? +its_handle_lpi(irq, regs); +continue; +} i
Re: [Xen-devel] [RFC PATCH 17/19] xen/arm: its: Support ITS interrupt handling
On Mon, 2 Mar 2015, vijay.kil...@gmail.com wrote: > From: Vijaya Kumar K > > Add support for handling ITS(LPI) interrupts. > The LPI interrupts are handled by physical ITS > driver. > > nested LPI interrupt handling is not tested and > enabled. > > Signed-off-by: Vijaya Kumar K > --- > xen/arch/arm/gic-v3-its.c | 31 +++ > xen/arch/arm/gic-v3.c |8 ++-- > xen/arch/arm/gic.c | 38 -- > xen/arch/arm/irq.c | 10 +++--- > xen/arch/arm/vgic-v3-its.c | 10 ++ > xen/arch/arm/vgic.c| 14 ++ > xen/include/asm-arm/gic.h |3 +++ > xen/include/asm-arm/irq.h |1 + > 8 files changed, 104 insertions(+), 11 deletions(-) > > diff --git a/xen/arch/arm/gic-v3-its.c b/xen/arch/arm/gic-v3-its.c > index b2c3320..7adbee4 100644 > --- a/xen/arch/arm/gic-v3-its.c > +++ b/xen/arch/arm/gic-v3-its.c > @@ -344,6 +344,37 @@ static const struct gic_its_hw_operations gic_its_ops = { > .gic_guest_lpi_type = &gic_guest_its_type, > }; > > +void its_handle_lpi(uint32_t irqnr, struct cpu_user_regs *regs) > +{ > +struct domain *d; > +struct irq_desc *desc = irq_to_desc(irqnr); > + > +irq_enter(); > +spin_lock(&desc->lock); > + > +if ( !desc->action ) > +{ > +printk("UNKNOWN LPI without handler\n"); > +goto err; > +} > + > +if ( desc->status & IRQ_GUEST ) > +{ > +d = irq_get_domain(desc); > + > +desc->handler->end(desc); > + > +desc->status |= IRQ_INPROGRESS; > +desc->arch.eoi_cpu = smp_processor_id(); > + > +/* XXX: inject irq into all guest vcpus */ > +vgic_vcpu_inject_irq(d->vcpu[0], irqnr); > +} Does it really need a separate handler? It seems to me that LPIs could just be handled from do_IRQ like the rest. Also the comment is wrong in this case. > +err: > +spin_unlock(&desc->lock); > +irq_exit(); > +} > + > static u64 its_cmd_ptr_to_offset(struct its_node *its, > struct its_cmd_block *ptr) > { > diff --git a/xen/arch/arm/gic-v3.c b/xen/arch/arm/gic-v3.c > index 02e71dd..b654535 100644 > --- a/xen/arch/arm/gic-v3.c > +++ b/xen/arch/arm/gic-v3.c > @@ -848,9 +848,13 @@ static void gicv3_update_lr(int lr, const struct > pending_irq *p, > > val = (((uint64_t)state & 0x3) << GICH_LR_STATE_SHIFT) | grp; > 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 ( is_lpi(p->irq) ) > +val |= ((uint64_t)p->desc->virq & GICH_LR_VIRTUAL_MASK) << > GICH_LR_VIRTUAL_SHIFT; > +else > +val |= ((uint64_t)p->irq & GICH_LR_VIRTUAL_MASK) << > GICH_LR_VIRTUAL_SHIFT; desc->virq should contain the right value for all interrupts, not just lpis, so you should be able to do: val |= ((uint64_t)p->desc-virq & GICH_LR_VIRTUAL_MASK) << GICH_LR_VIRTUAL_SHIFT; in all cases. > + 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 fb77387..c4d352a 100644 > --- a/xen/arch/arm/gic.c > +++ b/xen/arch/arm/gic.c > @@ -34,6 +34,7 @@ > #include > #include > #include > +#include > > static void gic_restore_pending_irqs(struct vcpu *v); > > @@ -134,6 +135,21 @@ void gic_route_irq_to_xen(struct irq_desc *desc, const > cpumask_t *cpu_mask, > gic_set_irq_properties(desc, cpu_mask, priority); > } > > +void gic_route_lpi_to_guest(struct domain *d, struct irq_desc *desc, > +const cpumask_t *cpu_mask, unsigned int priority) > +{ > +struct pending_irq *p; > +ASSERT(spin_is_locked(&desc->lock)); > + > +desc->handler = gic_its_hw_ops->gic_guest_lpi_type; > +set_bit(_IRQ_GUEST, &desc->status); > + > + > +/* TODO: do not assume delivery to vcpu0 */ > +p = irq_to_pending(d->vcpu[0], desc->irq); > +p->desc = desc; > +} > + > /* Program the GIC to route an interrupt to a guest > * - desc.lock must be held > */ > @@ -341,20 +357,33 @@ static void gic_update_one_lr(struct vcpu *v, int i) > struct pending_irq *p; > int irq; > struct gic_lr lr_val; > +uint32_t pirq; > > ASSERT(spin_is_locked(&v->arch.vgic.lock)); > ASSERT(!local_irq_is_enabled()); > > gic_hw_ops->read_lr(i, &lr_val); > irq = lr_val.virq; > -p = irq_to_pending(v, irq); > + > +if ( is_lpi(irq) ) > +{ > +// Fetch corresponding plpi for vlpi > +if ( vgic_its_get_pid(v, irq, &pirq) ) > +BUG(); > +p = irq_to_pending(v, pirq); > +irq = pirq; > +} > +else > +{ > +p = irq_to_pending(v, irq); Shouldn't p->desc->irq return the pirq for LPIs too? If it doesn't,
Re: [Xen-devel] [RFC PATCH 17/19] xen/arm: its: Support ITS interrupt handling
Hi Stefano, On 03/03/2015 18:07, Stefano Stabellini wrote: I would like to see a more generic handling of virq != physical irq. This is not specific to LPIs but to any scenario where the physical irq differs from the virtual irq. I though we talked about it during the meeting at Connect... I've already got a patch for making virq != pirq : https://patches.linaro.org/43012/ That would drop the static 8K added because of the changes in irq_desc. Regards, -- Julien Grall ___ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel
Re: [Xen-devel] [RFC PATCH 17/19] xen/arm: its: Support ITS interrupt handling
On Tue, 3 Mar 2015, Julien Grall wrote: > Hi Stefano, > > On 03/03/2015 18:07, Stefano Stabellini wrote: > > I would like to see a more generic handling of virq != physical irq. > > This is not specific to LPIs but to any scenario where the physical irq > > differs from the virtual irq. > > I though we talked about it during the meeting at Connect... > > I've already got a patch for making virq != pirq : > https://patches.linaro.org/43012/ > > That would drop the static 8K added because of the changes in irq_desc. I was pretty sure you had a patch for this already but I didn't have a link to it ready. Your patch could be a requirement for this series. ___ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel