aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/kvm/vgic.c
diff options
context:
space:
mode:
authorMarc Zyngier <marc.zyngier@arm.com>2013-01-21 19:36:15 -0500
committerMarc Zyngier <marc.zyngier@arm.com>2013-02-11 13:59:55 -0500
commit5863c2ce7269a7b24d60006430aa79a750b226ec (patch)
tree21f8d572c873dc4922a92939870de6987eb47cf7 /arch/arm/kvm/vgic.c
parenta1fcb44e26b0d98ebe53e8299462bf84c5aff178 (diff)
ARM: KVM: VGIC interrupt injection
Plug the interrupt injection code. Interrupts can now be generated from user space. Reviewed-by: Will Deacon <will.deacon@arm.com> Signed-off-by: Christoffer Dall <c.dall@virtualopensystems.com> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Diffstat (limited to 'arch/arm/kvm/vgic.c')
-rw-r--r--arch/arm/kvm/vgic.c117
1 files changed, 117 insertions, 0 deletions
diff --git a/arch/arm/kvm/vgic.c b/arch/arm/kvm/vgic.c
index 2d5e29f1c28f..2e6a585c23e5 100644
--- a/arch/arm/kvm/vgic.c
+++ b/arch/arm/kvm/vgic.c
@@ -73,6 +73,7 @@
73 73
74static void vgic_retire_disabled_irqs(struct kvm_vcpu *vcpu); 74static void vgic_retire_disabled_irqs(struct kvm_vcpu *vcpu);
75static void vgic_update_state(struct kvm *kvm); 75static void vgic_update_state(struct kvm *kvm);
76static void vgic_kick_vcpus(struct kvm *kvm);
76static void vgic_dispatch_sgi(struct kvm_vcpu *vcpu, u32 reg); 77static void vgic_dispatch_sgi(struct kvm_vcpu *vcpu, u32 reg);
77 78
78static u32 *vgic_bitmap_get_reg(struct vgic_bitmap *x, 79static u32 *vgic_bitmap_get_reg(struct vgic_bitmap *x,
@@ -708,6 +709,9 @@ bool vgic_handle_mmio(struct kvm_vcpu *vcpu, struct kvm_run *run,
708 kvm_prepare_mmio(run, mmio); 709 kvm_prepare_mmio(run, mmio);
709 kvm_handle_mmio_return(vcpu, run); 710 kvm_handle_mmio_return(vcpu, run);
710 711
712 if (updated_state)
713 vgic_kick_vcpus(vcpu->kvm);
714
711 return true; 715 return true;
712} 716}
713 717
@@ -1104,6 +1108,119 @@ int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu)
1104 return test_bit(vcpu->vcpu_id, &dist->irq_pending_on_cpu); 1108 return test_bit(vcpu->vcpu_id, &dist->irq_pending_on_cpu);
1105} 1109}
1106 1110
1111static void vgic_kick_vcpus(struct kvm *kvm)
1112{
1113 struct kvm_vcpu *vcpu;
1114 int c;
1115
1116 /*
1117 * We've injected an interrupt, time to find out who deserves
1118 * a good kick...
1119 */
1120 kvm_for_each_vcpu(c, vcpu, kvm) {
1121 if (kvm_vgic_vcpu_pending_irq(vcpu))
1122 kvm_vcpu_kick(vcpu);
1123 }
1124}
1125
1126static int vgic_validate_injection(struct kvm_vcpu *vcpu, int irq, int level)
1127{
1128 int is_edge = vgic_irq_is_edge(vcpu, irq);
1129 int state = vgic_dist_irq_is_pending(vcpu, irq);
1130
1131 /*
1132 * Only inject an interrupt if:
1133 * - edge triggered and we have a rising edge
1134 * - level triggered and we change level
1135 */
1136 if (is_edge)
1137 return level > state;
1138 else
1139 return level != state;
1140}
1141
1142static bool vgic_update_irq_state(struct kvm *kvm, int cpuid,
1143 unsigned int irq_num, bool level)
1144{
1145 struct vgic_dist *dist = &kvm->arch.vgic;
1146 struct kvm_vcpu *vcpu;
1147 int is_edge, is_level;
1148 int enabled;
1149 bool ret = true;
1150
1151 spin_lock(&dist->lock);
1152
1153 vcpu = kvm_get_vcpu(kvm, cpuid);
1154 is_edge = vgic_irq_is_edge(vcpu, irq_num);
1155 is_level = !is_edge;
1156
1157 if (!vgic_validate_injection(vcpu, irq_num, level)) {
1158 ret = false;
1159 goto out;
1160 }
1161
1162 if (irq_num >= VGIC_NR_PRIVATE_IRQS) {
1163 cpuid = dist->irq_spi_cpu[irq_num - VGIC_NR_PRIVATE_IRQS];
1164 vcpu = kvm_get_vcpu(kvm, cpuid);
1165 }
1166
1167 kvm_debug("Inject IRQ%d level %d CPU%d\n", irq_num, level, cpuid);
1168
1169 if (level)
1170 vgic_dist_irq_set(vcpu, irq_num);
1171 else
1172 vgic_dist_irq_clear(vcpu, irq_num);
1173
1174 enabled = vgic_irq_is_enabled(vcpu, irq_num);
1175
1176 if (!enabled) {
1177 ret = false;
1178 goto out;
1179 }
1180
1181 if (is_level && vgic_irq_is_active(vcpu, irq_num)) {
1182 /*
1183 * Level interrupt in progress, will be picked up
1184 * when EOId.
1185 */
1186 ret = false;
1187 goto out;
1188 }
1189
1190 if (level) {
1191 vgic_cpu_irq_set(vcpu, irq_num);
1192 set_bit(cpuid, &dist->irq_pending_on_cpu);
1193 }
1194
1195out:
1196 spin_unlock(&dist->lock);
1197
1198 return ret;
1199}
1200
1201/**
1202 * kvm_vgic_inject_irq - Inject an IRQ from a device to the vgic
1203 * @kvm: The VM structure pointer
1204 * @cpuid: The CPU for PPIs
1205 * @irq_num: The IRQ number that is assigned to the device
1206 * @level: Edge-triggered: true: to trigger the interrupt
1207 * false: to ignore the call
1208 * Level-sensitive true: activates an interrupt
1209 * false: deactivates an interrupt
1210 *
1211 * The GIC is not concerned with devices being active-LOW or active-HIGH for
1212 * level-sensitive interrupts. You can think of the level parameter as 1
1213 * being HIGH and 0 being LOW and all devices being active-HIGH.
1214 */
1215int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int irq_num,
1216 bool level)
1217{
1218 if (vgic_update_irq_state(kvm, cpuid, irq_num, level))
1219 vgic_kick_vcpus(kvm);
1220
1221 return 0;
1222}
1223
1107static bool vgic_ioaddr_overlap(struct kvm *kvm) 1224static bool vgic_ioaddr_overlap(struct kvm *kvm)
1108{ 1225{
1109 phys_addr_t dist = kvm->arch.vgic.vgic_dist_base; 1226 phys_addr_t dist = kvm->arch.vgic.vgic_dist_base;