/* Caller has already checked that the IRQ is an SPI */
ASSERT(virq >= 32);
ASSERT(virq < vgic_num_irqs(d));
+ ASSERT(!is_lpi(virq));
vgic_lock_rank(v_target, rank, flags);
ASSERT(spin_is_locked(&desc->lock));
ASSERT(test_bit(_IRQ_GUEST, &desc->status));
ASSERT(p->desc == desc);
+ ASSERT(!is_lpi(virq));
vgic_lock_rank(v_target, rank, flags);
{
struct pending_irq *n = irq_to_pending(v, virtual_irq);
+ /* If an LPI has been removed meanwhile, there is nothing left to raise. */
+ if ( unlikely(!n) )
+ return;
+
ASSERT(spin_is_locked(&v->arch.vgic.lock));
if ( list_empty(&n->lr_queue) )
{
int i;
unsigned int nr_lrs = gic_hw_ops->info->nr_lrs;
+ struct pending_irq *p = irq_to_pending(v, virtual_irq);
ASSERT(spin_is_locked(&v->arch.vgic.lock));
+ if ( unlikely(!p) )
+ /* An unmapped LPI does not need to be raised. */
+ return;
+
if ( v == current && list_empty(&v->arch.vgic.lr_pending) )
{
i = find_first_zero_bit(&this_cpu(lr_mask), nr_lrs);
if (i < nr_lrs) {
set_bit(i, &this_cpu(lr_mask));
- gic_set_lr(i, irq_to_pending(v, virtual_irq), GICH_LR_PENDING);
+ gic_set_lr(i, p, GICH_LR_PENDING);
return;
}
}
- gic_add_to_lr_pending(v, irq_to_pending(v, virtual_irq));
+ gic_add_to_lr_pending(v, p);
}
static void gic_update_one_lr(struct vcpu *v, int i)
gic_hw_ops->read_lr(i, &lr_val);
irq = lr_val.virq;
p = irq_to_pending(v, irq);
+ /* An LPI might have been unmapped, in which case we just clean up here. */
+ if ( unlikely(!p) )
+ {
+ ASSERT(is_lpi(irq));
+
+ gic_hw_ops->clear_lr(i);
+ clear_bit(i, &this_cpu(lr_mask));
+
+ return;
+ }
+
if ( lr_val.state & GICH_LR_ACTIVE )
{
set_bit(GIC_IRQ_GUEST_ACTIVE, &p->status);
unsigned long flags;
struct pending_irq *p;
+ /* This will never be called for an LPI, as we don't migrate them. */
+ ASSERT(!is_lpi(irq));
+
spin_lock_irqsave(&old->arch.vgic.lock, flags);
p = irq_to_pending(old, irq);
int i = 0;
struct vcpu *v_target;
+ /* LPIs will never be disabled via this function. */
+ ASSERT(!is_lpi(32 * n + 31));
+
while ( (i = find_next_bit(&mask, 32, i)) < 32 ) {
irq = i + (32 * n);
v_target = vgic_get_target_vcpu(v, irq);
struct vcpu *v_target;
struct domain *d = v->domain;
+ /* LPIs will never be enabled via this function. */
+ ASSERT(!is_lpi(32 * n + 31));
+
while ( (i = find_next_bit(&mask, 32, i)) < 32 ) {
irq = i + (32 * n);
v_target = vgic_get_target_vcpu(v, irq);
return true;
}
+/*
+ * Returns the pointer to the struct pending_irq belonging to the given
+ * interrupt.
+ * This can return NULL if called for an LPI which has been unmapped
+ * meanwhile.
+ */
struct pending_irq *irq_to_pending(struct vcpu *v, unsigned int irq)
{
struct pending_irq *n;
spin_lock_irqsave(&v->arch.vgic.lock, flags);
n = irq_to_pending(v, virq);
+ /* If an LPI has been removed, there is nothing to inject here. */
+ if ( unlikely(!n) )
+ {
+ spin_unlock_irqrestore(&v->arch.vgic.lock, flags);
+ return;
+ }
/* vcpu offline */
if ( test_bit(_VPF_down, &v->pause_flags) )
struct pending_irq *p = irq_to_pending(current,
current->domain->arch.evtchn_irq);
+ /* Does not work for LPIs. */
+ ASSERT(!is_lpi(current->domain->arch.evtchn_irq));
+
/* XXX: if the first interrupt has already been delivered, we should
* check whether any other interrupts with priority higher than the
* one in GICV_IAR are in the lr_pending queue or in the LR