Message ID | 1404406394-18231-5-git-send-email-stefano.stabellini@eu.citrix.com |
---|---|
State | New |
Headers | show |
On 07/03/2014 05:53 PM, Stefano Stabellini wrote: > diff --git a/xen/arch/arm/gic-v2.c b/xen/arch/arm/gic-v2.c > index 695c232..c3d2853 100644 > --- a/xen/arch/arm/gic-v2.c > +++ b/xen/arch/arm/gic-v2.c > @@ -532,9 +532,22 @@ static void gicv2_guest_irq_end(struct irq_desc *desc) > /* Deactivation happens in maintenance interrupt / via GICV */ > } > > -static void gicv2_irq_set_affinity(struct irq_desc *desc, const cpumask_t *mask) > +static void gicv2_irq_set_affinity(struct irq_desc *desc, const cpumask_t *cpu_mask) > { > - BUG(); > + volatile unsigned char *bytereg; > + unsigned int mask; > + > + ASSERT(!cpumask_empty(cpu_mask)); > + > + spin_lock(&gicv2.lock); > + > + mask = gicv2_cpu_mask(cpu_mask); > + > + /* Set target CPU mask (RAZ/WI on uniprocessor) */ > + bytereg = (unsigned char *) (GICD + GICD_ITARGETSR); > + bytereg[desc->irq] = mask; The new implemenation of GICv2 is using {read,write}* helpers. Can you use writeb_relaxed here, please? [..] > diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c > index b4493a3..69d3040 100644 > --- a/xen/arch/arm/vgic.c > +++ b/xen/arch/arm/vgic.c > @@ -399,6 +399,7 @@ static void vgic_migrate_irq(struct vcpu *old, struct vcpu *new, unsigned int ir > > if ( list_empty(&p->inflight) ) > { > + irq_set_affinity(p->desc, cpumask_of(new->processor)); > spin_unlock_irqrestore(&old->arch.vgic.lock, flags); > return; > } > @@ -407,6 +408,7 @@ static void vgic_migrate_irq(struct vcpu *old, struct vcpu *new, unsigned int ir > { > list_del_init(&p->lr_queue); > list_del_init(&p->inflight); > + irq_set_affinity(p->desc, cpumask_of(new->processor)); I think this irq_set_affinity is misplaced. You forgot to handle the case where the IRQ has been EOIed, and no IRQ has been queued. Also, it looks like this is done a bit late. the IRQ may fire on the previous physical CPU again at least once. This will happen the X-Gene quirk. Regards,
On Fri, 2014-07-04 at 11:51 +0100, Julien Grall wrote: > On 07/03/2014 05:53 PM, Stefano Stabellini wrote: > > diff --git a/xen/arch/arm/gic-v2.c b/xen/arch/arm/gic-v2.c > > index 695c232..c3d2853 100644 > > --- a/xen/arch/arm/gic-v2.c > > +++ b/xen/arch/arm/gic-v2.c > > @@ -532,9 +532,22 @@ static void gicv2_guest_irq_end(struct irq_desc *desc) > > /* Deactivation happens in maintenance interrupt / via GICV */ > > } > > > > -static void gicv2_irq_set_affinity(struct irq_desc *desc, const cpumask_t *mask) > > +static void gicv2_irq_set_affinity(struct irq_desc *desc, const cpumask_t *cpu_mask) > > { > > - BUG(); > > + volatile unsigned char *bytereg; > > + unsigned int mask; > > + > > + ASSERT(!cpumask_empty(cpu_mask)); > > + > > + spin_lock(&gicv2.lock); > > + > > + mask = gicv2_cpu_mask(cpu_mask); > > + > > + /* Set target CPU mask (RAZ/WI on uniprocessor) */ > > + bytereg = (unsigned char *) (GICD + GICD_ITARGETSR); > > + bytereg[desc->irq] = mask; > > The new implemenation of GICv2 is using {read,write}* helpers. Can you > use writeb_relaxed here, please? Now called writeb_gicd(mask, GICD_ITARGETSR + desc->irq) in staging... Ian.
On Fri, 4 Jul 2014, Julien Grall wrote: > On 07/03/2014 05:53 PM, Stefano Stabellini wrote: > > diff --git a/xen/arch/arm/gic-v2.c b/xen/arch/arm/gic-v2.c > > index 695c232..c3d2853 100644 > > --- a/xen/arch/arm/gic-v2.c > > +++ b/xen/arch/arm/gic-v2.c > > @@ -532,9 +532,22 @@ static void gicv2_guest_irq_end(struct irq_desc *desc) > > /* Deactivation happens in maintenance interrupt / via GICV */ > > } > > > > -static void gicv2_irq_set_affinity(struct irq_desc *desc, const cpumask_t *mask) > > +static void gicv2_irq_set_affinity(struct irq_desc *desc, const cpumask_t *cpu_mask) > > { > > - BUG(); > > + volatile unsigned char *bytereg; > > + unsigned int mask; > > + > > + ASSERT(!cpumask_empty(cpu_mask)); > > + > > + spin_lock(&gicv2.lock); > > + > > + mask = gicv2_cpu_mask(cpu_mask); > > + > > + /* Set target CPU mask (RAZ/WI on uniprocessor) */ > > + bytereg = (unsigned char *) (GICD + GICD_ITARGETSR); > > + bytereg[desc->irq] = mask; > > The new implemenation of GICv2 is using {read,write}* helpers. Can you > use writeb_relaxed here, please? > > [..] sure > > diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c > > index b4493a3..69d3040 100644 > > --- a/xen/arch/arm/vgic.c > > +++ b/xen/arch/arm/vgic.c > > @@ -399,6 +399,7 @@ static void vgic_migrate_irq(struct vcpu *old, struct vcpu *new, unsigned int ir > > > > if ( list_empty(&p->inflight) ) > > { > > + irq_set_affinity(p->desc, cpumask_of(new->processor)); > > spin_unlock_irqrestore(&old->arch.vgic.lock, flags); > > return; > > } > > @@ -407,6 +408,7 @@ static void vgic_migrate_irq(struct vcpu *old, struct vcpu *new, unsigned int ir > > { > > list_del_init(&p->lr_queue); > > list_del_init(&p->inflight); > > + irq_set_affinity(p->desc, cpumask_of(new->processor)); > > I think this irq_set_affinity is misplaced. You forgot to handle the > case where the IRQ has been EOIed, and no IRQ has been queued. If it was EOI'ed and cleared, then it falls into the first case above. If it was EOI'ed and not yet cleared, then it falls into the last case below. > Also, it looks like this is done a bit late. the IRQ may fire on the > previous physical CPU again at least once. > > This will happen the X-Gene quirk. That's not a problem, the case is handled correctly.
diff --git a/xen/arch/arm/gic-v2.c b/xen/arch/arm/gic-v2.c index 695c232..c3d2853 100644 --- a/xen/arch/arm/gic-v2.c +++ b/xen/arch/arm/gic-v2.c @@ -532,9 +532,22 @@ static void gicv2_guest_irq_end(struct irq_desc *desc) /* Deactivation happens in maintenance interrupt / via GICV */ } -static void gicv2_irq_set_affinity(struct irq_desc *desc, const cpumask_t *mask) +static void gicv2_irq_set_affinity(struct irq_desc *desc, const cpumask_t *cpu_mask) { - BUG(); + volatile unsigned char *bytereg; + unsigned int mask; + + ASSERT(!cpumask_empty(cpu_mask)); + + spin_lock(&gicv2.lock); + + mask = gicv2_cpu_mask(cpu_mask); + + /* Set target CPU mask (RAZ/WI on uniprocessor) */ + bytereg = (unsigned char *) (GICD + GICD_ITARGETSR); + bytereg[desc->irq] = mask; + + spin_unlock(&gicv2.lock); } /* XXX different for level vs edge */ diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c index be97261..37b08c2 100644 --- a/xen/arch/arm/gic.c +++ b/xen/arch/arm/gic.c @@ -397,6 +397,7 @@ static void gic_update_one_lr(struct vcpu *v, int i) /* vgic_get_target_vcpu takes the rank lock, ensuring * consistency with other itarget changes. */ v_target = vgic_get_target_vcpu(v, irq); + irq_set_affinity(p->desc, cpumask_of(v_target->processor)); vgic_vcpu_inject_irq(v_target, irq); spin_lock(&v->arch.vgic.lock); } diff --git a/xen/arch/arm/irq.c b/xen/arch/arm/irq.c index 49ca467..7150c7a 100644 --- a/xen/arch/arm/irq.c +++ b/xen/arch/arm/irq.c @@ -134,6 +134,12 @@ static inline struct domain *irq_get_domain(struct irq_desc *desc) return desc->action->dev_id; } +void irq_set_affinity(struct irq_desc *desc, const cpumask_t *cpu_mask) +{ + if ( desc != NULL ) + desc->handler->set_affinity(desc, cpu_mask); +} + int request_irq(unsigned int irq, unsigned int irqflags, void (*handler)(int, void *, struct cpu_user_regs *), const char *devname, void *dev_id) diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c index b4493a3..69d3040 100644 --- a/xen/arch/arm/vgic.c +++ b/xen/arch/arm/vgic.c @@ -399,6 +399,7 @@ static void vgic_migrate_irq(struct vcpu *old, struct vcpu *new, unsigned int ir if ( list_empty(&p->inflight) ) { + irq_set_affinity(p->desc, cpumask_of(new->processor)); spin_unlock_irqrestore(&old->arch.vgic.lock, flags); return; } @@ -407,6 +408,7 @@ static void vgic_migrate_irq(struct vcpu *old, struct vcpu *new, unsigned int ir { list_del_init(&p->lr_queue); list_del_init(&p->inflight); + irq_set_affinity(p->desc, cpumask_of(new->processor)); spin_unlock_irqrestore(&old->arch.vgic.lock, flags); vgic_vcpu_inject_irq(new, irq); return; @@ -422,6 +424,24 @@ static void vgic_migrate_irq(struct vcpu *old, struct vcpu *new, unsigned int ir spin_unlock_irqrestore(&old->arch.vgic.lock, flags); } +void arch_move_irqs(struct vcpu *v) +{ + const cpumask_t *cpu_mask = cpumask_of(v->processor); + struct domain *d = v->domain; + struct pending_irq *p; + struct vcpu *v_target; + int i; + + for ( i = 32; i < d->arch.vgic.nr_lines; 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); + } +} + static void vgic_disable_irqs(struct vcpu *v, uint32_t r, int n) { const unsigned long mask = r; @@ -477,6 +497,7 @@ static void vgic_enable_irqs(struct vcpu *v, uint32_t r, int n) } if ( p->desc != NULL ) { + irq_set_affinity(p->desc, cpumask_of(v_target->processor)); spin_lock_irqsave(&p->desc->lock, flags); p->desc->handler->enable(p->desc); spin_unlock_irqrestore(&p->desc->lock, flags); diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h index 839d053..6deb4bd 100644 --- a/xen/include/asm-arm/gic.h +++ b/xen/include/asm-arm/gic.h @@ -318,6 +318,7 @@ struct gic_hw_operations { void register_gic_ops(const struct gic_hw_operations *ops); struct vcpu *vgic_get_target_vcpu(struct vcpu *v, unsigned int irq); +void arch_move_irqs(struct vcpu *v); #endif /* __ASSEMBLY__ */ #endif diff --git a/xen/include/asm-arm/irq.h b/xen/include/asm-arm/irq.h index e567f71..dc282f0 100644 --- a/xen/include/asm-arm/irq.h +++ b/xen/include/asm-arm/irq.h @@ -48,6 +48,8 @@ int irq_set_spi_type(unsigned int spi, unsigned int type); int platform_get_irq(const struct dt_device_node *device, int index); +void irq_set_affinity(struct irq_desc *desc, const cpumask_t *cpu_mask); + #endif /* _ASM_HW_IRQ_H */ /* * Local variables: diff --git a/xen/include/asm-x86/irq.h b/xen/include/asm-x86/irq.h index 9066d38..d3c55f3 100644 --- a/xen/include/asm-x86/irq.h +++ b/xen/include/asm-x86/irq.h @@ -197,4 +197,6 @@ void cleanup_domain_irq_mapping(struct domain *); bool_t cpu_has_pending_apic_eoi(void); +static inline void arch_move_irqs(struct vcpu *v) { } + #endif /* _ASM_HW_IRQ_H */