static void vpl011_update_interrupt_status(struct domain *d) { struct vpl011 *vpl011 = &d->arch.vpl011; uint32_t uartmis = vpl011->uartris & vpl011->uartimsc; /* * This function is expected to be called with the lock taken. */ ASSERT(spin_is_locked(&vpl011->lock)); /* * TODO: PL011 interrupts are level triggered which means * that interrupt needs to be set/clear instead of being * injected. However, currently vGIC does not handle level * triggered interrupts properly. This function needs to be * revisited once vGIC starts handling level triggered * interrupts. */ /* * Raise an interrupt only if any additional interrupt * status bit has been set since the last time. */ if ( uartmis & ~vpl011->shadow_uartmis ) vgic_vcpu_inject_spi(d, GUEST_VPL011_SPI); vpl011->shadow_uartmis = uartmis; }
/* Dispatch an interrupt */ void do_IRQ(struct cpu_user_regs *regs, unsigned int irq, int is_fiq) { struct irq_desc *desc = irq_to_desc(irq); perfc_incr(irqs); ASSERT(irq >= 16); /* SGIs do not come down this path */ if (irq < 32) perfc_incr(ppis); else perfc_incr(spis); /* TODO: this_cpu(irq_count)++; */ irq_enter(); spin_lock(&desc->lock); desc->handler->ack(desc); if ( !desc->action ) { printk("Unknown %s %#3.3x\n", is_fiq ? "FIQ" : "IRQ", irq); goto out; } if ( test_bit(_IRQ_GUEST, &desc->status) ) { struct irq_guest *info = irq_get_guest_info(desc); perfc_incr(guest_irqs); desc->handler->end(desc); set_bit(_IRQ_INPROGRESS, &desc->status); /* * The irq cannot be a PPI, we only support delivery of SPIs to * guests. */ vgic_vcpu_inject_spi(info->d, info->virq); goto out_no_end; } set_bit(_IRQ_PENDING, &desc->status); /* * Since we set PENDING, if another processor is handling a different * instance of this same irq, the other processor will take care of it. */ if ( test_bit(_IRQ_DISABLED, &desc->status) || test_bit(_IRQ_INPROGRESS, &desc->status) ) goto out; set_bit(_IRQ_INPROGRESS, &desc->status); while ( test_bit(_IRQ_PENDING, &desc->status) ) { struct irqaction *action; clear_bit(_IRQ_PENDING, &desc->status); action = desc->action; spin_unlock_irq(&desc->lock); do { action->handler(irq, action->dev_id, regs); action = action->next; } while ( action ); spin_lock_irq(&desc->lock); } clear_bit(_IRQ_INPROGRESS, &desc->status); out: desc->handler->end(desc); out_no_end: spin_unlock(&desc->lock); irq_exit(); }