aboutsummaryrefslogtreecommitdiffstats
path: root/virt
diff options
context:
space:
mode:
authorMarc Zyngier <marc.zyngier@arm.com>2015-06-08 11:06:13 -0400
committerMarc Zyngier <marc.zyngier@arm.com>2015-08-12 06:28:25 -0400
commit08fd6461e8752d2db233c1f237fa5771bcefc63f (patch)
tree4c1e5d2ed88eece78975a83cde1995e7e9e36ae4 /virt
parent6c3d63c9a26ba56e2ca63a9f68d52f77ae551d91 (diff)
KVM: arm/arm64: vgic: Allow HW interrupts to be queued to a guest
To allow a HW interrupt to be injected into a guest, we lookup the guest virtual interrupt in the irq_phys_map list, and if we have a match, encode both interrupts in the LR. We also mark the interrupt as "active" at the host distributor level. On guest EOI on the virtual interrupt, the host interrupt will be deactivated. Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Diffstat (limited to 'virt')
-rw-r--r--virt/kvm/arm/vgic.c89
1 files changed, 86 insertions, 3 deletions
diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c
index 51c990075624..9d009d2f92f8 100644
--- a/virt/kvm/arm/vgic.c
+++ b/virt/kvm/arm/vgic.c
@@ -1140,6 +1140,39 @@ static void vgic_queue_irq_to_lr(struct kvm_vcpu *vcpu, int irq,
1140 if (!vgic_irq_is_edge(vcpu, irq)) 1140 if (!vgic_irq_is_edge(vcpu, irq))
1141 vlr.state |= LR_EOI_INT; 1141 vlr.state |= LR_EOI_INT;
1142 1142
1143 if (vlr.irq >= VGIC_NR_SGIS) {
1144 struct irq_phys_map *map;
1145 map = vgic_irq_map_search(vcpu, irq);
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) {
1155 int ret;
1156
1157 BUG_ON(!map->active);
1158 vlr.hwirq = map->phys_irq;
1159 vlr.state |= LR_HW;
1160 vlr.state &= ~LR_EOI_INT;
1161
1162 ret = irq_set_irqchip_state(map->irq,
1163 IRQCHIP_STATE_ACTIVE,
1164 true);
1165 WARN_ON(ret);
1166
1167 /*
1168 * Make sure we're not going to sample this
1169 * again, as a HW-backed interrupt cannot be
1170 * in the PENDING_ACTIVE stage.
1171 */
1172 vgic_irq_set_queued(vcpu, irq);
1173 }
1174 }
1175
1143 vgic_set_lr(vcpu, lr_nr, vlr); 1176 vgic_set_lr(vcpu, lr_nr, vlr);
1144 vgic_sync_lr_elrsr(vcpu, lr_nr, vlr); 1177 vgic_sync_lr_elrsr(vcpu, lr_nr, vlr);
1145} 1178}
@@ -1364,6 +1397,39 @@ static bool vgic_process_maintenance(struct kvm_vcpu *vcpu)
1364 return level_pending; 1397 return level_pending;
1365} 1398}
1366 1399
1400/*
1401 * Save the physical active state, and reset it to inactive.
1402 *
1403 * Return 1 if HW interrupt went from active to inactive, and 0 otherwise.
1404 */
1405static int vgic_sync_hwirq(struct kvm_vcpu *vcpu, struct vgic_lr vlr)
1406{
1407 struct irq_phys_map *map;
1408 int ret;
1409
1410 if (!(vlr.state & LR_HW))
1411 return 0;
1412
1413 map = vgic_irq_map_search(vcpu, vlr.irq);
1414 BUG_ON(!map || !map->active);
1415
1416 ret = irq_get_irqchip_state(map->irq,
1417 IRQCHIP_STATE_ACTIVE,
1418 &map->active);
1419
1420 WARN_ON(ret);
1421
1422 if (map->active) {
1423 ret = irq_set_irqchip_state(map->irq,
1424 IRQCHIP_STATE_ACTIVE,
1425 false);
1426 WARN_ON(ret);
1427 return 0;
1428 }
1429
1430 return 1;
1431}
1432
1367/* Sync back the VGIC state after a guest run */ 1433/* Sync back the VGIC state after a guest run */
1368static void __kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu) 1434static void __kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu)
1369{ 1435{
@@ -1378,14 +1444,31 @@ static void __kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu)
1378 elrsr = vgic_get_elrsr(vcpu); 1444 elrsr = vgic_get_elrsr(vcpu);
1379 elrsr_ptr = u64_to_bitmask(&elrsr); 1445 elrsr_ptr = u64_to_bitmask(&elrsr);
1380 1446
1381 /* Clear mappings for empty LRs */ 1447 /* Deal with HW interrupts, and clear mappings for empty LRs */
1382 for_each_set_bit(lr, elrsr_ptr, vgic->nr_lr) { 1448 for (lr = 0; lr < vgic->nr_lr; lr++) {
1383 struct vgic_lr vlr; 1449 struct vgic_lr vlr;
1384 1450
1385 if (!test_and_clear_bit(lr, vgic_cpu->lr_used)) 1451 if (!test_bit(lr, vgic_cpu->lr_used))
1386 continue; 1452 continue;
1387 1453
1388 vlr = vgic_get_lr(vcpu, lr); 1454 vlr = vgic_get_lr(vcpu, lr);
1455 if (vgic_sync_hwirq(vcpu, vlr)) {
1456 /*
1457 * So this is a HW interrupt that the guest
1458 * EOI-ed. Clean the LR state and allow the
1459 * interrupt to be sampled again.
1460 */
1461 vlr.state = 0;
1462 vlr.hwirq = 0;
1463 vgic_set_lr(vcpu, lr, vlr);
1464 vgic_irq_clear_queued(vcpu, vlr.irq);
1465 set_bit(lr, elrsr_ptr);
1466 }
1467
1468 if (!test_bit(lr, elrsr_ptr))
1469 continue;
1470
1471 clear_bit(lr, vgic_cpu->lr_used);
1389 1472
1390 BUG_ON(vlr.irq >= dist->nr_irqs); 1473 BUG_ON(vlr.irq >= dist->nr_irqs);
1391 vgic_cpu->vgic_irq_lr_map[vlr.irq] = LR_EMPTY; 1474 vgic_cpu->vgic_irq_lr_map[vlr.irq] = LR_EMPTY;