@@ -148,6 +148,7 @@ struct vgic_vm_ops {
int (*map_resources)(struct kvm *, const struct vgic_params *);
bool (*queue_lpis)(struct kvm_vcpu *);
void (*unqueue_lpi)(struct kvm_vcpu *, int irq);
+ bool (*check_lpis)(struct kvm_vcpu *);
int (*inject_msi)(struct kvm *, struct kvm_msi *);
};
@@ -381,6 +381,18 @@ out_unlock:
return ret;
}
+static bool its_is_enabled(struct kvm *kvm)
+{
+ return vgic_has_its(kvm) && kvm->arch.vgic.its.enabled &&
+ kvm->arch.vgic.lpis_enabled;
+}
+
+static bool lpi_is_pending(struct its_itte *itte, u32 vcpu_id)
+{
+ return itte->enabled && test_bit(vcpu_id, itte->pending) &&
+ itte->collection && (itte->collection->target_addr == vcpu_id);
+}
+
/*
* Find all enabled and pending LPIs and queue them into the list
* registers.
@@ -393,20 +405,12 @@ bool vits_queue_lpis(struct kvm_vcpu *vcpu)
struct its_itte *itte;
bool ret = true;
- if (!vgic_has_its(vcpu->kvm))
- return true;
- if (!its->enabled || !vcpu->kvm->arch.vgic.lpis_enabled)
+ if (!its_is_enabled(vcpu->kvm))
return true;
spin_lock(&its->lock);
for_each_lpi(device, itte, vcpu->kvm) {
- if (!itte->enabled || !test_bit(vcpu->vcpu_id, itte->pending))
- continue;
-
- if (!itte->collection)
- continue;
-
- if (itte->collection->target_addr != vcpu->vcpu_id)
+ if (!lpi_is_pending(itte, vcpu->vcpu_id))
continue;
@@ -436,6 +440,28 @@ void vits_unqueue_lpi(struct kvm_vcpu *vcpu, int lpi)
spin_unlock(&its->lock);
}
+bool vits_check_lpis(struct kvm_vcpu *vcpu)
+{
+ struct vgic_its *its = &vcpu->kvm->arch.vgic.its;
+ struct its_device *device;
+ struct its_itte *itte;
+ bool ret = false;
+
+ if (!its_is_enabled(vcpu->kvm))
+ return false;
+
+ spin_lock(&its->lock);
+ for_each_lpi(device, itte, vcpu->kvm) {
+ ret = lpi_is_pending(itte, vcpu->vcpu_id);
+ if (ret)
+ goto out;
+ }
+
+out:
+ spin_unlock(&its->lock);
+ return ret;
+}
+
static void its_free_itte(struct its_itte *itte)
{
list_del(&itte->itte_list);
@@ -41,6 +41,7 @@ int vits_inject_msi(struct kvm *kvm, struct kvm_msi *msi);
bool vits_queue_lpis(struct kvm_vcpu *vcpu);
void vits_unqueue_lpi(struct kvm_vcpu *vcpu, int irq);
+bool vits_check_lpis(struct kvm_vcpu *vcpu);
#define E_ITS_MOVI_UNMAPPED_INTERRUPT 0x010107
#define E_ITS_MOVI_UNMAPPED_COLLECTION 0x010109
@@ -966,6 +966,7 @@ void vgic_v3_init_emulation(struct kvm *kvm)
dist->vm_ops.inject_msi = vits_inject_msi;
dist->vm_ops.queue_lpis = vits_queue_lpis;
dist->vm_ops.unqueue_lpi = vits_unqueue_lpi;
+ dist->vm_ops.check_lpis = vits_check_lpis;
dist->vgic_dist_base = VGIC_ADDR_UNDEF;
dist->vgic_redist_base = VGIC_ADDR_UNDEF;
@@ -111,6 +111,14 @@ static void vgic_unqueue_lpi(struct kvm_vcpu *vcpu, int irq)
vcpu->kvm->arch.vgic.vm_ops.unqueue_lpi(vcpu, irq);
}
+static bool vgic_check_lpis(struct kvm_vcpu *vcpu)
+{
+ if (vcpu->kvm->arch.vgic.vm_ops.check_lpis)
+ return vcpu->kvm->arch.vgic.vm_ops.check_lpis(vcpu);
+ else
+ return false;
+}
+
int kvm_vgic_map_resources(struct kvm *kvm)
{
return kvm->arch.vgic.vm_ops.map_resources(kvm, vgic);
@@ -1036,8 +1044,11 @@ static int compute_pending_for_cpu(struct kvm_vcpu *vcpu)
pending_private = find_first_bit(pend_percpu, VGIC_NR_PRIVATE_IRQS);
pending_shared = find_first_bit(pend_shared, nr_shared);
- return (pending_private < VGIC_NR_PRIVATE_IRQS ||
- pending_shared < vgic_nr_shared_irqs(dist));
+ if (pending_private < VGIC_NR_PRIVATE_IRQS ||
+ pending_shared < vgic_nr_shared_irqs(dist))
+ return true;
+
+ return vgic_check_lpis(vcpu);
}
/*
@@ -1148,6 +1159,10 @@ static void vgic_retire_disabled_irqs(struct kvm_vcpu *vcpu)
for_each_clear_bit(lr, elrsr_ptr, vgic->nr_lr) {
struct vgic_lr vlr = vgic_get_lr(vcpu, lr);
+ /* We don't care about LPIs here */
+ if (vlr.irq >= 8192)
+ continue;
+
if (!vgic_irq_is_enabled(vcpu, vlr.irq)) {
vgic_retire_lr(lr, vcpu);
if (vgic_irq_is_queued(vcpu, vlr.irq))