aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristoffer Dall <christoffer.dall@linaro.org>2015-09-04 10:24:38 -0400
committerMarc Zyngier <marc.zyngier@arm.com>2015-09-04 11:26:52 -0400
commit04bdfa8ab5bab929cc57f73952c503a88372601d (patch)
tree3330f4c43a6d3a274186f729489b4aea5fa71621
parent054167b3d55127feb64978eddf3f9f3a84fe493b (diff)
arm/arm64: KVM: vgic: Move active state handling to flush_hwstate
We currently set the physical active state only when we *inject* a new pending virtual interrupt, but this is actually not correct, because we could have been preempted and run something else on the system that resets the active state to clear. This causes us to run the VM with the timer set to fire, but without setting the physical active state. The solution is to always check the LR configurations, and we if have a mapped interrupt in the LR in either the pending or active state (virtual), then set the physical active state. Acked-by: Marc Zyngier <marc.zyngier@arm.com> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
-rw-r--r--virt/kvm/arm/vgic.c42
1 files changed, 26 insertions, 16 deletions
diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c
index 9eb489a2c94c..6bd1c9bf7ae7 100644
--- a/virt/kvm/arm/vgic.c
+++ b/virt/kvm/arm/vgic.c
@@ -1144,26 +1144,11 @@ static void vgic_queue_irq_to_lr(struct kvm_vcpu *vcpu, int irq,
1144 struct irq_phys_map *map; 1144 struct irq_phys_map *map;
1145 map = vgic_irq_map_search(vcpu, irq); 1145 map = vgic_irq_map_search(vcpu, irq);
1146 1146
1147 /*
1148 * If we have a mapping, and the virtual interrupt is
1149 * being injected, then we must set the state to
1150 * active in the physical world. Otherwise the
1151 * physical interrupt will fire and the guest will
1152 * exit before processing the virtual interrupt.
1153 */
1154 if (map) { 1147 if (map) {
1155 int ret;
1156
1157 BUG_ON(!map->active);
1158 vlr.hwirq = map->phys_irq; 1148 vlr.hwirq = map->phys_irq;
1159 vlr.state |= LR_HW; 1149 vlr.state |= LR_HW;
1160 vlr.state &= ~LR_EOI_INT; 1150 vlr.state &= ~LR_EOI_INT;
1161 1151
1162 ret = irq_set_irqchip_state(map->irq,
1163 IRQCHIP_STATE_ACTIVE,
1164 true);
1165 WARN_ON(ret);
1166
1167 /* 1152 /*
1168 * Make sure we're not going to sample this 1153 * Make sure we're not going to sample this
1169 * again, as a HW-backed interrupt cannot be 1154 * again, as a HW-backed interrupt cannot be
@@ -1255,7 +1240,7 @@ static void __kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu)
1255 struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu; 1240 struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
1256 struct vgic_dist *dist = &vcpu->kvm->arch.vgic; 1241 struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
1257 unsigned long *pa_percpu, *pa_shared; 1242 unsigned long *pa_percpu, *pa_shared;
1258 int i, vcpu_id; 1243 int i, vcpu_id, lr, ret;
1259 int overflow = 0; 1244 int overflow = 0;
1260 int nr_shared = vgic_nr_shared_irqs(dist); 1245 int nr_shared = vgic_nr_shared_irqs(dist);
1261 1246
@@ -1310,6 +1295,31 @@ epilog:
1310 */ 1295 */
1311 clear_bit(vcpu_id, dist->irq_pending_on_cpu); 1296 clear_bit(vcpu_id, dist->irq_pending_on_cpu);
1312 } 1297 }
1298
1299 for (lr = 0; lr < vgic->nr_lr; lr++) {
1300 struct vgic_lr vlr;
1301
1302 if (!test_bit(lr, vgic_cpu->lr_used))
1303 continue;
1304
1305 vlr = vgic_get_lr(vcpu, lr);
1306
1307 /*
1308 * If we have a mapping, and the virtual interrupt is
1309 * presented to the guest (as pending or active), then we must
1310 * set the state to active in the physical world. See
1311 * Documentation/virtual/kvm/arm/vgic-mapped-irqs.txt.
1312 */
1313 if (vlr.state & LR_HW) {
1314 struct irq_phys_map *map;
1315 map = vgic_irq_map_search(vcpu, vlr.irq);
1316
1317 ret = irq_set_irqchip_state(map->irq,
1318 IRQCHIP_STATE_ACTIVE,
1319 true);
1320 WARN_ON(ret);
1321 }
1322 }
1313} 1323}
1314 1324
1315static bool vgic_process_maintenance(struct kvm_vcpu *vcpu) 1325static bool vgic_process_maintenance(struct kvm_vcpu *vcpu)