Skip to content

Commit 354920e

Browse files
author
Marc Zyngier
committed
KVM: arm64: vgic: Implement SW-driven deactivation
In order to deal with these systems that do not offer HW-based deactivation of interrupts, let implement a SW-based approach: - When the irq is queued into a LR, treat it as a pure virtual interrupt and set the EOI flag in the LR. - When the interrupt state is read back from the LR, force a deactivation when the state is invalid (neither active nor pending) Interrupts requiring such treatment get the VGIC_SW_RESAMPLE flag. Signed-off-by: Marc Zyngier <maz@kernel.org>
1 parent db75f1a commit 354920e

3 files changed

Lines changed: 40 additions & 8 deletions

File tree

arch/arm64/kvm/vgic/vgic-v2.c

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -108,11 +108,22 @@ void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu)
108108
* If this causes us to lower the level, we have to also clear
109109
* the physical active state, since we will otherwise never be
110110
* told when the interrupt becomes asserted again.
111+
*
112+
* Another case is when the interrupt requires a helping hand
113+
* on deactivation (no HW deactivation, for example).
111114
*/
112-
if (vgic_irq_is_mapped_level(irq) && (val & GICH_LR_PENDING_BIT)) {
113-
irq->line_level = vgic_get_phys_line_level(irq);
115+
if (vgic_irq_is_mapped_level(irq)) {
116+
bool resample = false;
117+
118+
if (val & GICH_LR_PENDING_BIT) {
119+
irq->line_level = vgic_get_phys_line_level(irq);
120+
resample = !irq->line_level;
121+
} else if (vgic_irq_needs_resampling(irq) &&
122+
!(irq->active || irq->pending_latch)) {
123+
resample = true;
124+
}
114125

115-
if (!irq->line_level)
126+
if (resample)
116127
vgic_irq_set_phys_active(irq, false);
117128
}
118129

@@ -152,7 +163,7 @@ void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr)
152163
if (irq->group)
153164
val |= GICH_LR_GROUP1;
154165

155-
if (irq->hw) {
166+
if (irq->hw && !vgic_irq_needs_resampling(irq)) {
156167
val |= GICH_LR_HW;
157168
val |= irq->hwintid << GICH_LR_PHYSID_CPUID_SHIFT;
158169
/*

arch/arm64/kvm/vgic/vgic-v3.c

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -101,11 +101,22 @@ void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu)
101101
* If this causes us to lower the level, we have to also clear
102102
* the physical active state, since we will otherwise never be
103103
* told when the interrupt becomes asserted again.
104+
*
105+
* Another case is when the interrupt requires a helping hand
106+
* on deactivation (no HW deactivation, for example).
104107
*/
105-
if (vgic_irq_is_mapped_level(irq) && (val & ICH_LR_PENDING_BIT)) {
106-
irq->line_level = vgic_get_phys_line_level(irq);
108+
if (vgic_irq_is_mapped_level(irq)) {
109+
bool resample = false;
110+
111+
if (val & ICH_LR_PENDING_BIT) {
112+
irq->line_level = vgic_get_phys_line_level(irq);
113+
resample = !irq->line_level;
114+
} else if (vgic_irq_needs_resampling(irq) &&
115+
!(irq->active || irq->pending_latch)) {
116+
resample = true;
117+
}
107118

108-
if (!irq->line_level)
119+
if (resample)
109120
vgic_irq_set_phys_active(irq, false);
110121
}
111122

@@ -136,7 +147,7 @@ void vgic_v3_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr)
136147
}
137148
}
138149

139-
if (irq->hw) {
150+
if (irq->hw && !vgic_irq_needs_resampling(irq)) {
140151
val |= ICH_LR_HW;
141152
val |= ((u64)irq->hwintid) << ICH_LR_PHYS_ID_SHIFT;
142153
/*

include/kvm/arm_vgic.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,11 @@ enum vgic_irq_config {
9999
* kvm_arm_get_running_vcpu() to get the vcpu pointer for private IRQs.
100100
*/
101101
struct irq_ops {
102+
/* Per interrupt flags for special-cased interrupts */
103+
unsigned long flags;
104+
105+
#define VGIC_IRQ_SW_RESAMPLE BIT(0) /* Clear the active state for resampling */
106+
102107
/*
103108
* Callback function pointer to in-kernel devices that can tell us the
104109
* state of the input level of mapped level-triggered IRQ faster than
@@ -150,6 +155,11 @@ struct vgic_irq {
150155
for in-kernel devices. */
151156
};
152157

158+
static inline bool vgic_irq_needs_resampling(struct vgic_irq *irq)
159+
{
160+
return irq->ops && (irq->ops->flags & VGIC_IRQ_SW_RESAMPLE);
161+
}
162+
153163
struct vgic_register_region;
154164
struct vgic_its;
155165

0 commit comments

Comments
 (0)