aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndre Przywara <andre.przywara@arm.com>2016-07-15 07:43:37 -0400
committerMarc Zyngier <marc.zyngier@arm.com>2016-07-18 13:14:38 -0400
commit2891a7dfb6c4a273996f0047660a75e88e3b8690 (patch)
treed703ea96114d917700aa5091c8287e844ce1b789
parentdf9f58fbea9bc656b5a7770c885c97b26255b234 (diff)
KVM: arm64: vgic-its: Implement MSI injection in ITS emulation
When userland wants to inject an MSI into the guest, it uses the KVM_SIGNAL_MSI ioctl, which carries the doorbell address along with the payload and the device ID. With the help of the KVM IO bus framework we learn the corresponding ITS from the doorbell address. We then use our wrapper functions to iterate the linked lists and find the proper Interrupt Translation Table Entry (ITTE) and thus the corresponding struct vgic_irq to finally set the pending bit. We also provide the handler for the ITS "INT" command, which allows a guest to trigger an MSI via the ITS command queue. Since this one knows about the right ITS already, we directly call the MMIO handler function without using the kvm_io_bus framework. Signed-off-by: Andre Przywara <andre.przywara@arm.com> Reviewed-by: Marc Zyngier <marc.zyngier@arm.com> Tested-by: Eric Auger <eric.auger@redhat.com> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
-rw-r--r--virt/kvm/arm/vgic/vgic-its.c77
-rw-r--r--virt/kvm/arm/vgic/vgic.h6
2 files changed, 83 insertions, 0 deletions
diff --git a/virt/kvm/arm/vgic/vgic-its.c b/virt/kvm/arm/vgic/vgic-its.c
index 1408c88d063e..d8e8f14135b4 100644
--- a/virt/kvm/arm/vgic/vgic-its.c
+++ b/virt/kvm/arm/vgic/vgic-its.c
@@ -437,6 +437,65 @@ static unsigned long vgic_mmio_read_its_idregs(struct kvm *kvm,
437 return 0; 437 return 0;
438} 438}
439 439
440/*
441 * Find the target VCPU and the LPI number for a given devid/eventid pair
442 * and make this IRQ pending, possibly injecting it.
443 * Must be called with the its_lock mutex held.
444 */
445static void vgic_its_trigger_msi(struct kvm *kvm, struct vgic_its *its,
446 u32 devid, u32 eventid)
447{
448 struct its_itte *itte;
449
450 if (!its->enabled)
451 return;
452
453 itte = find_itte(its, devid, eventid);
454 /* Triggering an unmapped IRQ gets silently dropped. */
455 if (itte && its_is_collection_mapped(itte->collection)) {
456 struct kvm_vcpu *vcpu;
457
458 vcpu = kvm_get_vcpu(kvm, itte->collection->target_addr);
459 if (vcpu && vcpu->arch.vgic_cpu.lpis_enabled) {
460 spin_lock(&itte->irq->irq_lock);
461 itte->irq->pending = true;
462 vgic_queue_irq_unlock(kvm, itte->irq);
463 }
464 }
465}
466
467/*
468 * Queries the KVM IO bus framework to get the ITS pointer from the given
469 * doorbell address.
470 * We then call vgic_its_trigger_msi() with the decoded data.
471 */
472int vgic_its_inject_msi(struct kvm *kvm, struct kvm_msi *msi)
473{
474 u64 address;
475 struct kvm_io_device *kvm_io_dev;
476 struct vgic_io_device *iodev;
477
478 if (!vgic_has_its(kvm))
479 return -ENODEV;
480
481 if (!(msi->flags & KVM_MSI_VALID_DEVID))
482 return -EINVAL;
483
484 address = (u64)msi->address_hi << 32 | msi->address_lo;
485
486 kvm_io_dev = kvm_io_bus_get_dev(kvm, KVM_MMIO_BUS, address);
487 if (!kvm_io_dev)
488 return -ENODEV;
489
490 iodev = container_of(kvm_io_dev, struct vgic_io_device, dev);
491
492 mutex_lock(&iodev->its->its_lock);
493 vgic_its_trigger_msi(kvm, iodev->its, msi->devid, msi->data);
494 mutex_unlock(&iodev->its->its_lock);
495
496 return 0;
497}
498
440/* Requires the its_lock to be held. */ 499/* Requires the its_lock to be held. */
441static void its_free_itte(struct kvm *kvm, struct its_itte *itte) 500static void its_free_itte(struct kvm *kvm, struct its_itte *itte)
442{ 501{
@@ -897,6 +956,21 @@ static int vgic_its_cmd_handle_movall(struct kvm *kvm, struct vgic_its *its,
897} 956}
898 957
899/* 958/*
959 * The INT command injects the LPI associated with that DevID/EvID pair.
960 * Must be called with the its_lock mutex held.
961 */
962static int vgic_its_cmd_handle_int(struct kvm *kvm, struct vgic_its *its,
963 u64 *its_cmd)
964{
965 u32 msi_data = its_cmd_get_id(its_cmd);
966 u64 msi_devid = its_cmd_get_deviceid(its_cmd);
967
968 vgic_its_trigger_msi(kvm, its, msi_devid, msi_data);
969
970 return 0;
971}
972
973/*
900 * This function is called with the its_cmd lock held, but the ITS data 974 * This function is called with the its_cmd lock held, but the ITS data
901 * structure lock dropped. 975 * structure lock dropped.
902 */ 976 */
@@ -932,6 +1006,9 @@ static int vgic_its_handle_command(struct kvm *kvm, struct vgic_its *its,
932 case GITS_CMD_MOVALL: 1006 case GITS_CMD_MOVALL:
933 ret = vgic_its_cmd_handle_movall(kvm, its, its_cmd); 1007 ret = vgic_its_cmd_handle_movall(kvm, its, its_cmd);
934 break; 1008 break;
1009 case GITS_CMD_INT:
1010 ret = vgic_its_cmd_handle_int(kvm, its, its_cmd);
1011 break;
935 case GITS_CMD_INV: 1012 case GITS_CMD_INV:
936 ret = vgic_its_cmd_handle_inv(kvm, its, its_cmd); 1013 ret = vgic_its_cmd_handle_inv(kvm, its, its_cmd);
937 break; 1014 break;
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index ee348deb8737..9d557f25cbfc 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -78,6 +78,7 @@ int vgic_v3_map_resources(struct kvm *kvm);
78int vgic_register_redist_iodevs(struct kvm *kvm, gpa_t dist_base_address); 78int vgic_register_redist_iodevs(struct kvm *kvm, gpa_t dist_base_address);
79bool vgic_has_its(struct kvm *kvm); 79bool vgic_has_its(struct kvm *kvm);
80void vgic_enable_lpis(struct kvm_vcpu *vcpu); 80void vgic_enable_lpis(struct kvm_vcpu *vcpu);
81int vgic_its_inject_msi(struct kvm *kvm, struct kvm_msi *msi);
81#else 82#else
82static inline void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu) 83static inline void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu)
83{ 84{
@@ -138,6 +139,11 @@ static inline bool vgic_has_its(struct kvm *kvm)
138static inline void vgic_enable_lpis(struct kvm_vcpu *vcpu) 139static inline void vgic_enable_lpis(struct kvm_vcpu *vcpu)
139{ 140{
140} 141}
142
143static inline int vgic_its_inject_msi(struct kvm *kvm, struct kvm_msi *msi)
144{
145 return -ENODEV;
146}
141#endif 147#endif
142 148
143int kvm_register_vgic_device(unsigned long type); 149int kvm_register_vgic_device(unsigned long type);