Skip to content

Commit 8e44474

Browse files
committed
KVM: arm/arm64: vgic-new: Add IRQ sorting
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 <[email protected]> Signed-off-by: Andre Przywara <[email protected]> Reviewed-by: Eric Auger <[email protected]> Reviewed-by: Marc Zyngier <[email protected]>
1 parent 81eeb95 commit 8e44474

File tree

1 file changed

+57
-0
lines changed

1 file changed

+57
-0
lines changed

virt/kvm/arm/vgic/vgic.c

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
#include <linux/kvm.h>
1818
#include <linux/kvm_host.h>
19+
#include <linux/list_sort.h>
1920

2021
#include "vgic.h"
2122

@@ -102,6 +103,62 @@ static struct kvm_vcpu *vgic_target_oracle(struct vgic_irq *irq)
102103
return NULL;
103104
}
104105

106+
/*
107+
* The order of items in the ap_lists defines how we'll pack things in LRs as
108+
* well, the first items in the list being the first things populated in the
109+
* LRs.
110+
*
111+
* A hard rule is that active interrupts can never be pushed out of the LRs
112+
* (and therefore take priority) since we cannot reliably trap on deactivation
113+
* of IRQs and therefore they have to be present in the LRs.
114+
*
115+
* Otherwise things should be sorted by the priority field and the GIC
116+
* hardware support will take care of preemption of priority groups etc.
117+
*
118+
* Return negative if "a" sorts before "b", 0 to preserve order, and positive
119+
* to sort "b" before "a".
120+
*/
121+
static int vgic_irq_cmp(void *priv, struct list_head *a, struct list_head *b)
122+
{
123+
struct vgic_irq *irqa = container_of(a, struct vgic_irq, ap_list);
124+
struct vgic_irq *irqb = container_of(b, struct vgic_irq, ap_list);
125+
bool penda, pendb;
126+
int ret;
127+
128+
spin_lock(&irqa->irq_lock);
129+
spin_lock_nested(&irqb->irq_lock, SINGLE_DEPTH_NESTING);
130+
131+
if (irqa->active || irqb->active) {
132+
ret = (int)irqb->active - (int)irqa->active;
133+
goto out;
134+
}
135+
136+
penda = irqa->enabled && irqa->pending;
137+
pendb = irqb->enabled && irqb->pending;
138+
139+
if (!penda || !pendb) {
140+
ret = (int)pendb - (int)penda;
141+
goto out;
142+
}
143+
144+
/* Both pending and enabled, sort by priority */
145+
ret = irqa->priority - irqb->priority;
146+
out:
147+
spin_unlock(&irqb->irq_lock);
148+
spin_unlock(&irqa->irq_lock);
149+
return ret;
150+
}
151+
152+
/* Must be called with the ap_list_lock held */
153+
static void vgic_sort_ap_list(struct kvm_vcpu *vcpu)
154+
{
155+
struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
156+
157+
DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&vgic_cpu->ap_list_lock));
158+
159+
list_sort(NULL, &vgic_cpu->ap_list_head, vgic_irq_cmp);
160+
}
161+
105162
/*
106163
* Only valid injection if changing level for level-triggered IRQs or for a
107164
* rising edge.

0 commit comments

Comments
 (0)