Commit 04c11093222579128ed4c0448024190ec7f4e212
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) |