Skip to content

Commit

Permalink
KVM: arm/arm64: vgic-new: Add IRQ sorting
Browse files Browse the repository at this point in the history
Adds the sorting function to cover the case where you have more IRQs
to consider than you have LRs. We now consider priorities.

Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
Reviewed-by: Eric Auger <eric.auger@linaro.org>
Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
  • Loading branch information
Christoffer Dall committed May 20, 2016
1 parent 81eeb95 commit 8e44474
Showing 1 changed file with 57 additions and 0 deletions.
57 changes: 57 additions & 0 deletions virt/kvm/arm/vgic/vgic.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

#include <linux/kvm.h>
#include <linux/kvm_host.h>
#include <linux/list_sort.h>

#include "vgic.h"

Expand Down Expand Up @@ -102,6 +103,62 @@ static struct kvm_vcpu *vgic_target_oracle(struct vgic_irq *irq)
return NULL;
}

/*
* The order of items in the ap_lists defines how we'll pack things in LRs as
* well, the first items in the list being the first things populated in the
* LRs.
*
* A hard rule is that active interrupts can never be pushed out of the LRs
* (and therefore take priority) since we cannot reliably trap on deactivation
* of IRQs and therefore they have to be present in the LRs.
*
* Otherwise things should be sorted by the priority field and the GIC
* hardware support will take care of preemption of priority groups etc.
*
* Return negative if "a" sorts before "b", 0 to preserve order, and positive
* to sort "b" before "a".
*/
static int vgic_irq_cmp(void *priv, struct list_head *a, struct list_head *b)
{
struct vgic_irq *irqa = container_of(a, struct vgic_irq, ap_list);
struct vgic_irq *irqb = container_of(b, struct vgic_irq, ap_list);
bool penda, pendb;
int ret;

spin_lock(&irqa->irq_lock);
spin_lock_nested(&irqb->irq_lock, SINGLE_DEPTH_NESTING);

if (irqa->active || irqb->active) {
ret = (int)irqb->active - (int)irqa->active;
goto out;
}

penda = irqa->enabled && irqa->pending;
pendb = irqb->enabled && irqb->pending;

if (!penda || !pendb) {
ret = (int)pendb - (int)penda;
goto out;
}

/* Both pending and enabled, sort by priority */
ret = irqa->priority - irqb->priority;
out:
spin_unlock(&irqb->irq_lock);
spin_unlock(&irqa->irq_lock);
return ret;
}

/* Must be called with the ap_list_lock held */
static void vgic_sort_ap_list(struct kvm_vcpu *vcpu)
{
struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;

DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&vgic_cpu->ap_list_lock));

list_sort(NULL, &vgic_cpu->ap_list_head, vgic_irq_cmp);
}

/*
* Only valid injection if changing level for level-triggered IRQs or for a
* rising edge.
Expand Down

0 comments on commit 8e44474

Please sign in to comment.