Commit 04c11093222579128ed4c0448024190ec7f4e212

Authored by Eric Auger
Committed by Marc Zyngier
1 parent 6e4076735d

KVM: arm/arm64: Implement KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION

Now all the internals are ready to handle multiple redistributor
regions, let's allow the userspace to register them.

Signed-off-by: Eric Auger <eric.auger@redhat.com>
Reviewed-by: Christoffer Dall <christoffer.dall@arm.com>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>

Showing 4 changed files with 67 additions and 4 deletions Side-by-side Diff

virt/kvm/arm/vgic/vgic-kvm-device.c
... ... @@ -92,7 +92,7 @@
92 92 if (r)
93 93 break;
94 94 if (write) {
95   - r = vgic_v3_set_redist_base(kvm, *addr);
  95 + r = vgic_v3_set_redist_base(kvm, 0, *addr, 0);
96 96 goto out;
97 97 }
98 98 rdreg = list_first_entry(&vgic->rd_regions,
... ... @@ -103,6 +103,43 @@
103 103 addr_ptr = &rdreg->base;
104 104 break;
105 105 }
  106 + case KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION:
  107 + {
  108 + struct vgic_redist_region *rdreg;
  109 + u8 index;
  110 +
  111 + r = vgic_check_type(kvm, KVM_DEV_TYPE_ARM_VGIC_V3);
  112 + if (r)
  113 + break;
  114 +
  115 + index = *addr & KVM_VGIC_V3_RDIST_INDEX_MASK;
  116 +
  117 + if (write) {
  118 + gpa_t base = *addr & KVM_VGIC_V3_RDIST_BASE_MASK;
  119 + u32 count = (*addr & KVM_VGIC_V3_RDIST_COUNT_MASK)
  120 + >> KVM_VGIC_V3_RDIST_COUNT_SHIFT;
  121 + u8 flags = (*addr & KVM_VGIC_V3_RDIST_FLAGS_MASK)
  122 + >> KVM_VGIC_V3_RDIST_FLAGS_SHIFT;
  123 +
  124 + if (!count || flags)
  125 + r = -EINVAL;
  126 + else
  127 + r = vgic_v3_set_redist_base(kvm, index,
  128 + base, count);
  129 + goto out;
  130 + }
  131 +
  132 + rdreg = vgic_v3_rdist_region_from_index(kvm, index);
  133 + if (!rdreg) {
  134 + r = -ENOENT;
  135 + goto out;
  136 + }
  137 +
  138 + *addr = index;
  139 + *addr |= rdreg->base;
  140 + *addr |= (u64)rdreg->count << KVM_VGIC_V3_RDIST_COUNT_SHIFT;
  141 + goto out;
  142 + }
106 143 default:
107 144 r = -ENODEV;
108 145 }
... ... @@ -674,6 +711,7 @@
674 711 switch (attr->attr) {
675 712 case KVM_VGIC_V3_ADDR_TYPE_DIST:
676 713 case KVM_VGIC_V3_ADDR_TYPE_REDIST:
  714 + case KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION:
677 715 return 0;
678 716 }
679 717 break;
virt/kvm/arm/vgic/vgic-mmio-v3.c
... ... @@ -764,11 +764,11 @@
764 764 return ret;
765 765 }
766 766  
767   -int vgic_v3_set_redist_base(struct kvm *kvm, u64 addr)
  767 +int vgic_v3_set_redist_base(struct kvm *kvm, u32 index, u64 addr, u32 count)
768 768 {
769 769 int ret;
770 770  
771   - ret = vgic_v3_insert_redist_region(kvm, 0, addr, 0);
  771 + ret = vgic_v3_insert_redist_region(kvm, index, addr, count);
772 772 if (ret)
773 773 return ret;
774 774  
virt/kvm/arm/vgic/vgic-v3.c
... ... @@ -491,6 +491,20 @@
491 491 return NULL;
492 492 }
493 493  
  494 +struct vgic_redist_region *vgic_v3_rdist_region_from_index(struct kvm *kvm,
  495 + u32 index)
  496 +{
  497 + struct list_head *rd_regions = &kvm->arch.vgic.rd_regions;
  498 + struct vgic_redist_region *rdreg;
  499 +
  500 + list_for_each_entry(rdreg, rd_regions, list) {
  501 + if (rdreg->index == index)
  502 + return rdreg;
  503 + }
  504 + return NULL;
  505 +}
  506 +
  507 +
494 508 int vgic_v3_map_resources(struct kvm *kvm)
495 509 {
496 510 struct vgic_dist *dist = &kvm->arch.vgic;
virt/kvm/arm/vgic/vgic.h
... ... @@ -96,6 +96,13 @@
96 96 /* we only support 64 kB translation table page size */
97 97 #define KVM_ITS_L1E_ADDR_MASK GENMASK_ULL(51, 16)
98 98  
  99 +#define KVM_VGIC_V3_RDIST_INDEX_MASK GENMASK_ULL(11, 0)
  100 +#define KVM_VGIC_V3_RDIST_FLAGS_MASK GENMASK_ULL(15, 12)
  101 +#define KVM_VGIC_V3_RDIST_FLAGS_SHIFT 12
  102 +#define KVM_VGIC_V3_RDIST_BASE_MASK GENMASK_ULL(51, 16)
  103 +#define KVM_VGIC_V3_RDIST_COUNT_MASK GENMASK_ULL(63, 52)
  104 +#define KVM_VGIC_V3_RDIST_COUNT_SHIFT 52
  105 +
99 106 /* Requires the irq_lock to be held by the caller. */
100 107 static inline bool irq_is_pending(struct vgic_irq *irq)
101 108 {
... ... @@ -215,7 +222,7 @@
215 222 int vgic_v3_map_resources(struct kvm *kvm);
216 223 int vgic_v3_lpi_sync_pending_status(struct kvm *kvm, struct vgic_irq *irq);
217 224 int vgic_v3_save_pending_tables(struct kvm *kvm);
218   -int vgic_v3_set_redist_base(struct kvm *kvm, u64 addr);
  225 +int vgic_v3_set_redist_base(struct kvm *kvm, u32 index, u64 addr, u32 count);
219 226 int vgic_register_redist_iodev(struct kvm_vcpu *vcpu);
220 227 bool vgic_v3_check_base(struct kvm *kvm);
221 228  
... ... @@ -284,6 +291,10 @@
284 291 else
285 292 return rdreg->count * KVM_VGIC_V3_REDIST_SIZE;
286 293 }
  294 +
  295 +struct vgic_redist_region *vgic_v3_rdist_region_from_index(struct kvm *kvm,
  296 + u32 index);
  297 +
287 298 bool vgic_v3_rdist_overlap(struct kvm *kvm, gpa_t base, size_t size);
288 299  
289 300 static inline bool vgic_dist_overlap(struct kvm *kvm, gpa_t base, size_t size)