[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH 5/5] xen/arm: Only enable physical IRQs when the guest asks
If the guest VCPU receives an interrupts when it's disabled, it will throw away the IRQ with EOIed it. This is result to lost IRQ forever. Directly EOIed the interrupt doesn't help because the IRQ could be fired again and result to an infinited loop. It happens during dom0 boot on the versatile express TC2 with the ethernet card. Let the interrupt disabled when Xen setups the route and enable it when Linux asks to enable it. Signed-off-by: Julien Grall <julien.grall@xxxxxxxxxx> --- xen/arch/arm/domain_build.c | 14 ++++++++++++++ xen/arch/arm/gic.c | 25 +++++++++++++++++++++++-- xen/arch/arm/vgic.c | 7 +++---- xen/include/asm-arm/gic.h | 4 ++++ xen/include/asm-arm/irq.h | 6 ++++++ 5 files changed, 50 insertions(+), 6 deletions(-) diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c index f5befbd..0470a2d 100644 --- a/xen/arch/arm/domain_build.c +++ b/xen/arch/arm/domain_build.c @@ -408,6 +408,20 @@ static int map_device(struct domain *d, const struct dt_device_node *dev) } DPRINT("irq %u = %u type = 0x%x\n", i, irq.irq, irq.type); + + /* + * Only map SGI interrupt in the guest as XEN won't handle + * it correctly. + * TODO: Fix it + */ + if ( !irq_is_sgi(irq.irq) ) + { + printk(XENLOG_WARNING "WARNING: Don't map irq %u for %s has " + "XEN doesn't handle properly non-SGI interrupt\n", + i, dt_node_full_name(dev)); + continue; + } + /* Don't check return because the IRQ can be use by multiple device */ gic_route_irq_to_guest(d, &irq, dt_node_name(dev)); } diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c index b16ba8c..e7d082a 100644 --- a/xen/arch/arm/gic.c +++ b/xen/arch/arm/gic.c @@ -179,6 +179,17 @@ static hw_irq_controller gic_guest_irq_type = { .set_affinity = gic_irq_set_affinity, }; +void gic_irq_enable(struct irq_desc *desc) +{ + spin_lock_irq(&desc->lock); + spin_lock(&gic.lock); + + desc->handler->enable(desc); + + spin_unlock(&gic.lock); + spin_unlock_irq(&desc->lock); +} + /* needs to be called with gic.lock held */ static void gic_set_irq_properties(unsigned int irq, bool_t level, unsigned int cpu_mask, unsigned int priority) @@ -543,8 +554,6 @@ static int __setup_irq(struct irq_desc *desc, unsigned int irq, desc->status &= ~IRQ_DISABLED; dsb(); - desc->handler->startup(desc); - return 0; } @@ -560,6 +569,8 @@ int __init setup_dt_irq(const struct dt_irq *irq, struct irqaction *new) rc = __setup_irq(desc, irq->irq, new); + desc->handler->startup(desc); + spin_unlock_irqrestore(&desc->lock, flags); return rc; @@ -711,6 +722,7 @@ void gic_inject(void) gic_inject_irq_start(); } +/* TODO: Handle properly non SGI-interrupt */ int gic_route_irq_to_guest(struct domain *d, const struct dt_irq *irq, const char * devname) { @@ -719,11 +731,18 @@ int gic_route_irq_to_guest(struct domain *d, const struct dt_irq *irq, unsigned long flags; int retval; bool_t level; + struct pending_irq *p; + /* XXX: handler other VCPU than 0 */ + struct vcpu *v = d->vcpu[0]; action = xmalloc(struct irqaction); if (!action) return -ENOMEM; + /* XXX: Here we assume a 1:1 interrupt mapping between the host and dom0 */ + BUG_ON(irq->irq >= (d->arch.vgic.nr_lines + NR_LOCAL_IRQS)); + p = irq_to_pending(v, irq->irq); + action->dev_id = d; action->name = devname; action->free_on_release = 1; @@ -744,6 +763,8 @@ int gic_route_irq_to_guest(struct domain *d, const struct dt_irq *irq, goto out; } + p->desc = desc; + out: spin_unlock(&gic.lock); spin_unlock_irqrestore(&desc->lock, flags); diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c index cea9233..4f3d816 100644 --- a/xen/arch/arm/vgic.c +++ b/xen/arch/arm/vgic.c @@ -372,6 +372,9 @@ static void vgic_enable_irqs(struct vcpu *v, uint32_t r, int n) if ( !list_empty(&p->inflight) && !gic_irq_injected(irq) ) gic_set_guest_irq(v, irq, GICH_LR_PENDING, p->priority); + if ( p->desc != NULL ) + gic_irq_enable(p->desc); + i++; } } @@ -685,10 +688,6 @@ void vgic_vcpu_inject_irq(struct vcpu *v, unsigned int irq, int virtual) n->irq = irq; n->priority = priority; - if (!virtual) - n->desc = irq_to_desc(irq); - else - n->desc = NULL; /* the irq is enabled */ if ( rank->ienable & (1 << (irq % 32)) ) diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h index f9e9ef1..f7f3c1e 100644 --- a/xen/include/asm-arm/gic.h +++ b/xen/include/asm-arm/gic.h @@ -134,6 +134,7 @@ #ifndef __ASSEMBLY__ #include <xen/device_tree.h> +#include <xen/irq.h> extern int domain_vgic_init(struct domain *d); extern void domain_vgic_free(struct domain *d); @@ -154,6 +155,9 @@ extern void gic_inject(void); extern void gic_clear_pending_irqs(struct vcpu *v); extern int gic_events_need_delivery(void); +/* Helper to enable an IRQ and take all the needed locks */ +extern void gic_irq_enable(struct irq_desc *desc); + extern void __cpuinit init_maintenance_interrupt(void); extern void gic_set_guest_irq(struct vcpu *v, unsigned int irq, unsigned int state, unsigned int priority); diff --git a/xen/include/asm-arm/irq.h b/xen/include/asm-arm/irq.h index 80ff68d..346dc1d 100644 --- a/xen/include/asm-arm/irq.h +++ b/xen/include/asm-arm/irq.h @@ -46,6 +46,12 @@ int __init request_dt_irq(const struct dt_irq *irq, void *dev_id); int __init setup_dt_irq(const struct dt_irq *irq, struct irqaction *new); +#define FIRST_SGI_IRQ 32 +static inline bool_t irq_is_sgi(unsigned int irq) +{ + return (irq >= FIRST_SGI_IRQ); +} + #endif /* _ASM_HW_IRQ_H */ /* * Local variables: -- 1.7.10.4 _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx http://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |